From 216c348c354c571c9961d8f391665364da371229 Mon Sep 17 00:00:00 2001 From: Catena cyber <35799796+catenacyber@users.noreply.github.com> Date: Thu, 21 May 2020 10:15:12 +0200 Subject: [PATCH] Oss-fuzz ideal integration (#1262) * Fix watchpoint leak in ARM * Builds fuzz targets with sanitizer support * Builds fuzz targets with directory driver * Adds script to dowlonad public corpus * Adds CIfuzz To checks Pull Requests with fuzzing * Use static library for fuzz targets * Less verbose logs for fuzz driver directory --- .github/workflows/cifuzz.yml | 23 ++++++++++ .travis.yml | 33 +++++++++++++++ qemu/target-arm/unicorn_arm.c | 1 + tests/fuzz/Makefile | 4 +- tests/fuzz/dlcorpus.sh | 11 +++++ tests/fuzz/onedir.c | 80 +++++++++++++++++++++++++++++++++++ 6 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/cifuzz.yml create mode 100644 tests/fuzz/dlcorpus.sh create mode 100644 tests/fuzz/onedir.c diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml new file mode 100644 index 00000000..f4259d6b --- /dev/null +++ b/.github/workflows/cifuzz.yml @@ -0,0 +1,23 @@ +name: CIFuzz +on: [pull_request] +jobs: + Fuzzing: + runs-on: ubuntu-latest + steps: + - name: Build Fuzzers + uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master + with: + oss-fuzz-project-name: 'unicorn' + dry-run: false + - name: Run Fuzzers + uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master + with: + oss-fuzz-project-name: 'unicorn' + fuzz-seconds: 600 + dry-run: false + - name: Upload Crash + uses: actions/upload-artifact@v1 + if: failure() + with: + name: artifacts + path: ./out/artifacts diff --git a/.travis.yml b/.travis.yml index 5de4988d..2b021068 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,39 @@ matrix: - PATH=$PATH:/usr/local/opt/binutils/bin script: make && make -C tests/unit test && make -C tests/regress test + - name: "Linux clang ASAN" + os: linux + compiler: clang + env: + - PATH=$PATH:/usr/local/opt/binutils/bin + - ASAN_OPTIONS=detect_leaks=0 + - CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link" + - CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link" + - LDFLAGS="-fsanitize=address" + script: make && make -C tests/fuzz && sh tests/fuzz/dlcorpus.sh + + - name: "Linux clang MSAN" + os: linux + compiler: clang + env: + - PATH=$PATH:/usr/local/opt/binutils/bin + - ASAN_OPTIONS=detect_leaks=0 + - CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=memory -fsanitize=fuzzer-no-link" + - CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=memory -fsanitize=fuzzer-no-link" + - LDFLAGS="-fsanitize=memory" + script: make && make -C tests/fuzz && sh tests/fuzz/dlcorpus.sh + + - name: "Linux clang USAN" + os: linux + compiler: clang + env: + - PATH=$PATH:/usr/local/opt/binutils/bin + - ASAN_OPTIONS=detect_leaks=0 + - CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=undefined -fsanitize=fuzzer-no-link" + - CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=undefined -fsanitize=fuzzer-no-link" + - LDFLAGS="-fsanitize=undefined" + script: make && make -C tests/fuzz && sh tests/fuzz/dlcorpus.sh + - name: "Linux 32bit" os: linux compiler: gcc diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 0e1b1828..4264477d 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -32,6 +32,7 @@ void arm_release(void* ctx) g_free(cpu->cpreg_values); g_free(cpu->cpreg_vmstate_indexes); g_free(cpu->cpreg_vmstate_values); + cpu_watchpoint_remove_all(CPU(cpu), BP_CPU); release_common(ctx); } diff --git a/tests/fuzz/Makefile b/tests/fuzz/Makefile index e3a4f070..c0b6946e 100644 --- a/tests/fuzz/Makefile +++ b/tests/fuzz/Makefile @@ -6,7 +6,7 @@ ifeq ($(UNAME_S), Linux) LDFLAGS += -lrt endif -LDFLAGS += -lunicorn +LDFLAGS += ../../libunicorn.a ALL_TESTS_SOURCES = $(wildcard fuzz*.c) @@ -20,4 +20,4 @@ clean: rm -rf ${ALL_TESTS} fuzz%: fuzz%.c - $(CC) $(CFLAGS) $^ onefile.c $(LDFLAGS) -o $@ + $(CC) $(CFLAGS) $^ onedir.c $(LDFLAGS) -o $@ diff --git a/tests/fuzz/dlcorpus.sh b/tests/fuzz/dlcorpus.sh new file mode 100644 index 00000000..f159e80c --- /dev/null +++ b/tests/fuzz/dlcorpus.sh @@ -0,0 +1,11 @@ +#/bin/sh +#change to script directory +cd `dirname $0` +ls fuzz_emu*.c | sed 's/.c//' | while read target +do + #download public corpus + wget "https://storage.googleapis.com/unicorn-backup.clusterfuzz-external.appspot.com/corpus/libFuzzer/unicorn_$target/public.zip" + unzip -q public.zip -d corpus_$target + #run target on corpus + ./$target corpus_$target +done diff --git a/tests/fuzz/onedir.c b/tests/fuzz/onedir.c new file mode 100644 index 00000000..21f9a768 --- /dev/null +++ b/tests/fuzz/onedir.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +int main(int argc, char** argv) +{ + FILE * fp; + uint8_t Data[0x1000]; + size_t Size; + DIR *d; + struct dirent *dir; + int r = 0; + int i; + + if (argc != 2) { + return 1; + } + + d = opendir(argv[1]); + if (d == NULL) { + printf("Invalid directory\n"); + return 2; + } + if (chdir(argv[1]) != 0) { + closedir(d); + printf("Invalid directory\n"); + return 2; + } + + printf("Starting directory %s\n", argv[1]); + while((dir = readdir(d)) != NULL) { + //opens the file, get its size, and reads it into a buffer + if (dir->d_type != DT_REG) { + continue; + } + //printf("Running file %s\n", dir->d_name); + fflush(stdout); + fp = fopen(dir->d_name, "rb"); + if (fp == NULL) { + r = 3; + break; + } + if (fseek(fp, 0L, SEEK_END) != 0) { + fclose(fp); + r = 4; + break; + } + Size = ftell(fp); + if (Size == (size_t) -1) { + fclose(fp); + r = 5; + break; + } else if (Size > 0x1000) { + fclose(fp); + continue; + } + if (fseek(fp, 0L, SEEK_SET) != 0) { + fclose(fp); + r = 7; + break; + } + if (fread(Data, Size, 1, fp) != 1) { + fclose(fp); + r = 8; + break; + } + + //lauch fuzzer + LLVMFuzzerTestOneInput(Data, Size); + fclose(fp); + } + closedir(d); + printf("Ok : whole directory finished %s\n", argv[1]); + return r; +} +