From 96ae86cb8c17ea456073810f461240e78942b31f Mon Sep 17 00:00:00 2001
From: Dominik Loidolt <dominik.loidolt@univie.ac.at>
Date: Fri, 19 Apr 2024 12:29:54 +0200
Subject: [PATCH] Add github action to enable batch fuzzing with
 ClusterFuzzLite

Batch fuzzing enables continuous, regular fuzzing on your latest HEAD and
allows a corpus of inputs to build up over time, which greatly improves the
effectiveness of fuzzing. Batch fuzzing can be run on a cron schedule.
---
 .clusterfuzzlite/build.sh          |  5 +---
 .github/workflows/cflite_batch.yml | 37 ++++++++++++++++++++++++++++++
 test/fuzz/download_corpus.sh       | 33 ++++++++++++++++++++++++++
 test/fuzz/fuzz_compression.c       |  1 +
 test/fuzz/fuzz_round_trip.c        |  1 +
 test/fuzz/meson.build              | 10 ++++----
 6 files changed, 77 insertions(+), 10 deletions(-)
 create mode 100644 .github/workflows/cflite_batch.yml
 create mode 100755 test/fuzz/download_corpus.sh

diff --git a/.clusterfuzzlite/build.sh b/.clusterfuzzlite/build.sh
index ed72b56..43f11d8 100755
--- a/.clusterfuzzlite/build.sh
+++ b/.clusterfuzzlite/build.sh
@@ -6,8 +6,6 @@ BUILD=$WORK/build
 rm -rf "$BUILD"
 mkdir -p "$BUILD"
 
-echo "$LIB_FUZZING_ENGINE"
-
 # setup project
 meson setup "$BUILD" \
   --buildtype=plain \
@@ -15,8 +13,7 @@ meson setup "$BUILD" \
   -Dfuzzer_ldflags="$LIB_FUZZING_ENGINE" \
   -Ddebug_level=0 \
   -Ddefault_library=static \
-  -Db_lundef=false \
-  --wrap-mode=nodownload
+  -Db_lundef=false 
 
 # build fuzzers
 ninja -v -C "$BUILD" test/fuzz/fuzz_{round_trip,compression}
diff --git a/.github/workflows/cflite_batch.yml b/.github/workflows/cflite_batch.yml
new file mode 100644
index 0000000..30a6b53
--- /dev/null
+++ b/.github/workflows/cflite_batch.yml
@@ -0,0 +1,37 @@
+name: ClusterFuzzLite batch fuzzing
+on:
+  schedule:
+    - cron: '0 0/6 * * *'  # Every 6th hour. Change this to whatever is suitable.
+  push:
+    branches: test_batch_fuzzing
+
+permissions: read-all
+jobs:
+  BatchFuzzing:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        sanitizer:
+        - address
+        - undefined
+        - memory
+    steps:
+    - name: Build Fuzzers (${{ matrix.sanitizer }})
+      id: build
+      uses: google/clusterfuzzlite/actions/build_fuzzers@v1
+      with:
+        language: c
+        sanitizer: ${{ matrix.sanitizer }}
+    - name: Run Fuzzers (${{ matrix.sanitizer }})
+      id: run
+      uses: google/clusterfuzzlite/actions/run_fuzzers@v1
+      with:
+        github-token: ${{ secrets.GITHUB_TOKEN }}
+        fuzz-seconds: 3600
+        mode: 'batch'
+        sanitizer: ${{ matrix.sanitizer }}
+        output-sarif: true
+        storage-repo: https://gh-action:${{ secrets.ACCESS_TOKEN_GITLAB_UNI }}@gitlab.phaidra.org/loidoltd15/cmp_tool_storage.git
+        storage-repo-branch: main
+        storage-repo-branch-coverage: gh-pages
diff --git a/test/fuzz/download_corpus.sh b/test/fuzz/download_corpus.sh
new file mode 100755
index 0000000..5b11d24
--- /dev/null
+++ b/test/fuzz/download_corpus.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+bin_path=${1:-}
+if [[ -z "$bin_path" ]]; then
+    echo "usage: $0 <fuzz target>"
+    exit 1
+fi
+
+if [[ "$OSTYPE" == "darwin"* ]]; then
+    DOWNLOAD="curl --silent -L -o"
+else
+    DOWNLOAD="wget --quiet --output-document"
+fi
+
+ROOT_DIR=${MESON_BUILD_ROOT:-.}"/"
+CORPORA_URL=https://gitlab.phaidra.org/loidoltd15/cmp_tool_storage/-/archive/main/cmp_tool_storage-main.tar.bz2
+CORPUS_COMPRESSED=$ROOT_DIR"cmp_tool_storage.tar.bz2"
+CORPUS="cmp_tool_storage-main"
+
+CORPUS_ID=$(git ls-remote https://gitlab.phaidra.org/loidoltd15/cmp_tool_storage.git HEAD | head -c 8)
+CORPUS_DIR="$ROOT_DIR"corpus__"$CORPUS_ID"
+
+if [ ! -d "$CORPUS_DIR" ]; then
+    $DOWNLOAD "$CORPUS_COMPRESSED" "$CORPORA_URL"
+    mkdir "$CORPUS_DIR"
+    tar -xf "$CORPUS_COMPRESSED" -C "$CORPUS_DIR"
+fi
+rm -f "$CORPUS_COMPRESSED"
+
+for arg in "$@" 
+do
+    find "$CORPUS_DIR"/"$CORPUS"/corpus -name "$arg"
+done
diff --git a/test/fuzz/fuzz_compression.c b/test/fuzz/fuzz_compression.c
index 64d92ba..1c91d34 100644
--- a/test/fuzz/fuzz_compression.c
+++ b/test/fuzz/fuzz_compression.c
@@ -95,6 +95,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 	case CMP_ERROR_PAR_SPECIFIC:
 	case CMP_ERROR_PAR_BUFFERS:
 	case CMP_ERROR_PAR_MAX_USED_BITS:
+	case CMP_ERROR_PAR_NULL:
 	/* chunk errors */
 	case CMP_ERROR_CHUNK_NULL:
 	case CMP_ERROR_CHUNK_TOO_LARGE:
diff --git a/test/fuzz/fuzz_round_trip.c b/test/fuzz/fuzz_round_trip.c
index 0a6a1a7..4ee9bd8 100644
--- a/test/fuzz/fuzz_round_trip.c
+++ b/test/fuzz/fuzz_round_trip.c
@@ -175,6 +175,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 	case CMP_ERROR_PAR_SPECIFIC:
 	case CMP_ERROR_PAR_BUFFERS:
 	case CMP_ERROR_PAR_MAX_USED_BITS:
+	case CMP_ERROR_PAR_NULL:
 	/* chunk errors */
 	case CMP_ERROR_CHUNK_NULL:
 	case CMP_ERROR_CHUNK_TOO_LARGE:
diff --git a/test/fuzz/meson.build b/test/fuzz/meson.build
index 02a8ebe..f7da779 100644
--- a/test/fuzz/meson.build
+++ b/test/fuzz/meson.build
@@ -7,8 +7,6 @@ fuzz_targets = ['fuzz_compression.c', 'fuzz_round_trip.c']
 
 add_languages('cpp', native: false) # libFuzzingEngine needs c++
 
-
-
 foreach target : fuzz_targets
   file_name = target
   target_name = file_name.split('.').get(0)
@@ -21,11 +19,11 @@ foreach target : fuzz_targets
     link_language : 'cpp' # libFuzzingEngine needs c++
   )
 
-# todo add seed corpus
+   corpus_path = run_command('./download_corpus.sh', target_name, check: true).stdout().split()
+
   test(target_name + ' 10 min',
     fuzz_exe,
-    args : ['-rss_limit_mb=2560', '-timeout=25', '-max_total_time=600'],
-    # args : ['-timeout=25', '-max_total_time=600'],
+    args : ['-rss_limit_mb=2560', '-timeout=25', '-max_total_time=600', corpus_path],
     env : test_env,
     is_parallel : false,
     # suite : 'fuzzing',
@@ -34,7 +32,7 @@ foreach target : fuzz_targets
 
   test(target_name + ' non stop',
     fuzz_exe,
-    args : ['-rss_limit_mb=2560', '-timeout=25'],
+    args : ['-rss_limit_mb=2560', '-timeout=25', corpus_path],
     env : test_env,
     is_parallel : false,
     # suite : 'fuzzing',
-- 
GitLab