diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index d24714e..4489535 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -5,21 +5,32 @@ enable_language(CXX) include_directories(PUBLIC ${CMAKE_SOURCE_DIR}) include_directories(PUBLIC ${PROJECT_BINARY_DIR}) +# This sets up either the standalone runner or the user supplied libfuzzing +# engine. We're using the standalone runner for unit testing alone at the +# moment to make the sure the fuzzer builds and runs appropriately. if(DEFINED ENV{LIB_FUZZING_ENGINE}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} $ENV{LIB_FUZZING_ENGINE}") - set(fuzzing_engine "") + set(FUZZING_ENGINE "") else() add_library(fuzzing_engine standalone_runner.cc) - set(fuzzing_engine fuzzing_engine) + set(FUZZING_ENGINE fuzzing_engine) endif() foreach(FUZZERNAME + bad_fuzzer tokener_parse_ex_fuzzer) add_executable(${FUZZERNAME} ${FUZZERNAME}.cc) target_link_libraries(${FUZZERNAME} json-c - ${fuzzing_engine}) + ${FUZZING_ENGINE}) - add_test(NAME test_${FUZZERNAME} COMMAND ${CMAKE_BINARY_DIR}/fuzz/${FUZZERNAME} ${CMAKE_SOURCE_DIR}/fuzz/tests/valid.json) + file(GLOB TESTFILES "${CMAKE_SOURCE_DIR}/fuzz/tests/*.json") + foreach(TESTFILE ${TESTFILES}) + get_filename_component(FILENAME ${TESTFILE} NAME_WE) + add_test(NAME test_${FUZZERNAME}_${FILENAME} + COMMAND ${CMAKE_BINARY_DIR}/fuzz/${FUZZERNAME} + ${TESTFILE}) + + endforeach(TESTFILE) endforeach(FUZZERNAME) diff --git a/fuzz/README.md b/fuzz/README.md index 237c1da..8962690 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -4,3 +4,23 @@ This directory contains fuzzers that target [llvm's LibFuzzer](https://llvm.org/docs/LibFuzzer.html). They are built and run automatically by Google's [OSS-Fuzz](https://github.com/google/oss-fuzz/) infrastructure. + +## How do I test or run the fuzzers like oss-fuzz? + +``` +git clone https://github.com/google/oss-fuzz.git +cd oss-fuzz +python infra/helper.py build_image json-c +python infra/helper.py build_fuzzers --sanitizer address --engine libfuzzer --architecture x86_64 json-c +python infra/helper.py run_fuzzer json-c tokener_parse_ex_fuzzer +``` + +## How do I add new unit or regression tests for the fuzzer? + +The tests directory contains json files that can be used to either test the fuzzer itself or be used as regression tests. As long as the files end in `.json`, cmake will pick them up and generate a Ctest test case. If/when oss-fuzz finds a bug with a fuzzer, simply pull that test case into the `./tests` directory and it will serve as a regression test. + +Note - the fuzzers are not being run with sanitizers in this repository's CI at the moment; we're strictly building them here to ensure that they function. + +## How do I reproduce a failure form a fuzzer? + +Use [the steps detailed on OSS-fuzz](https://google.github.io/oss-fuzz/advanced-topics/reproducing/). diff --git a/fuzz/bad_fuzzer.cc b/fuzz/bad_fuzzer.cc new file mode 100644 index 0000000..6d71c43 --- /dev/null +++ b/fuzz/bad_fuzzer.cc @@ -0,0 +1,9 @@ +#include + +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + int *array = new int[100]; + delete [] array; + return array[size]; // BOOM +} diff --git a/fuzz/build.sh b/fuzz/build.sh index 3864015..a723496 100755 --- a/fuzz/build.sh +++ b/fuzz/build.sh @@ -15,13 +15,22 @@ # ################################################################################ # this is expected to be run only by oss-fuzz. It will run from $SRC (above json-c) -cp $SRC/json-c/fuzz/*.dict $OUT/ +cp $SRC/json-c/fuzz/*.dict "$OUT/" BUILD="$SRC/json-c/build" -mkdir $BUILD -cd $BUILD +zip -j "$SRC/corpus.zip" "$SRC/go-fuzz-corpus/json/corpus" + +mkdir "$BUILD" +cd "$BUILD" cmake -DCMAKE_C_FLAGS="$CFLAGS" -DCMAKE_CXX_FLAGS="$CXXFLAGS" -DBUILD_SHARED_LIBS=OFF .. make -j$(nproc) -cp fuzz/*_fuzzer $OUT/ +cp fuzz/*_fuzzer "$OUT/" + +fuzzerFiles=$(find fuzz/ -name "*_fuzzer") +for F in $fuzzerFiles; do + FN=$(basename -- $F) + cp "$SRC/corpus.zip" "$OUT/${FN}_seed_corpus.zip" +done +# for fuzzer in fuzz copy the json corpus as a zip file