From 100e5549b6e27bc48d6133be0941ea6bfd4b75ac Mon Sep 17 00:00:00 2001 From: Max Dymond Date: Fri, 28 Jun 2019 13:22:51 +0100 Subject: [PATCH 1/2] Create a fuzzing target for jansson --- .travis.yml | 2 + Makefile.am | 12 ++++++ ossfuzz/json_load_fuzzer.cc | 11 ++++++ ossfuzz/ossfuzz.sh | 28 ++++++++++++++ ossfuzz/standaloneengine.cc | 74 +++++++++++++++++++++++++++++++++++++ ossfuzz/testinput.h | 3 ++ ossfuzz/travisoss.sh | 26 +++++++++++++ 7 files changed, 156 insertions(+) create mode 100644 ossfuzz/json_load_fuzzer.cc create mode 100755 ossfuzz/ossfuzz.sh create mode 100644 ossfuzz/standaloneengine.cc create mode 100644 ossfuzz/testinput.h create mode 100755 ossfuzz/travisoss.sh diff --git a/.travis.yml b/.travis.yml index 5b23c94..449e9bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ env: - JANSSON_BUILD_METHOD=cmake JANSSON_CMAKE_OPTIONS="-DJANSSON_TEST_WITH_VALGRIND=ON" JANSSON_EXTRA_INSTALL="valgrind" - JANSSON_BUILD_METHOD=autotools - JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl" + - JANSSON_BUILD_METHOD=fuzzer language: c compiler: - gcc @@ -20,3 +21,4 @@ script: - if [ "$JANSSON_BUILD_METHOD" = "autotools" ]; then autoreconf -f -i && CFLAGS=-Werror ./configure && make check; fi - if [ "$JANSSON_BUILD_METHOD" = "cmake" ]; then mkdir build && cd build && cmake $JANSSON_CMAKE_OPTIONS .. && cmake --build . && ctest --output-on-failure; fi - if [ "$JANSSON_BUILD_METHOD" = "coverage" ]; then mkdir build && cd build && cmake $JANSSON_CMAKE_OPTIONS .. && cmake --build . && cmake --build . --target coveralls; fi + - if [ "$JANSSON_BUILD_METHOD" = "fuzzer" ]; then ./ossfuzz/travisoss.sh; fi diff --git a/Makefile.am b/Makefile.am index 0de2ac1..3e3dc09 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,3 +8,15 @@ dvi: pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = jansson.pc + + +# Add fuzzing support +LIB_FUZZING_ENGINE ?= standaloneengine.o + +ossfuzz/%.o: ossfuzz/%.cc + $(CXX) -c -Isrc $(CXXFLAGS) $< -o $@ + +.PHONY: json_load_fuzzer +json_load_fuzzer: ossfuzz/json_load_fuzzer.o src/.libs/libjansson.a + $(CXX) -c $(CXXFLAGS) ossfuzz/standaloneengine.cc -o standaloneengine.o + $(CXX) $(CXXFLAGS) $(LIB_FUZZING_ENGINE) $^ -o $@$(EXT) diff --git a/ossfuzz/json_load_fuzzer.cc b/ossfuzz/json_load_fuzzer.cc new file mode 100644 index 0000000..09e7da5 --- /dev/null +++ b/ossfuzz/json_load_fuzzer.cc @@ -0,0 +1,11 @@ +#include + +#include "jansson.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + json_error_t error; + auto jobj = json_loadb(reinterpret_cast(data), size, 0, &error); + if (jobj) + json_decref(jobj); + return 0; +} diff --git a/ossfuzz/ossfuzz.sh b/ossfuzz/ossfuzz.sh new file mode 100755 index 0000000..897e5a6 --- /dev/null +++ b/ossfuzz/ossfuzz.sh @@ -0,0 +1,28 @@ +#!/bin/bash -eu + +# This script is called by the oss-fuzz main project when compiling the fuzz +# targets. This script is regression tested by travisoss.sh. + +# Save off the current folder as the build root. +export BUILD_ROOT=$PWD + +echo "CC: $CC" +echo "CXX: $CXX" +echo "LIB_FUZZING_ENGINE: $LIB_FUZZING_ENGINE" +echo "CFLAGS: $CFLAGS" +echo "CXXFLAGS: $CXXFLAGS" +echo "OUT: $OUT" + +export MAKEFLAGS+="-j$(nproc)" + +# Install dependencies +apt-get -y install automake libtool + +# Compile the fuzzer. +autoreconf -i +./configure +make +make json_load_fuzzer + +# Copy the fuzzer to the output directory. +cp -v json_load_fuzzer $OUT/ diff --git a/ossfuzz/standaloneengine.cc b/ossfuzz/standaloneengine.cc new file mode 100644 index 0000000..175360e --- /dev/null +++ b/ossfuzz/standaloneengine.cc @@ -0,0 +1,74 @@ +#include +#include +#include + +#include "testinput.h" + +/** + * Main procedure for standalone fuzzing engine. + * + * Reads filenames from the argument array. For each filename, read the file + * into memory and then call the fuzzing interface with the data. + */ +int main(int argc, char **argv) +{ + int ii; + for(ii = 1; ii < argc; ii++) + { + FILE *infile; + printf("[%s] ", argv[ii]); + + /* Try and open the file. */ + infile = fopen(argv[ii], "rb"); + if(infile) + { + uint8_t *buffer = NULL; + size_t buffer_len; + + printf("Opened.. "); + + /* Get the length of the file. */ + fseek(infile, 0L, SEEK_END); + buffer_len = ftell(infile); + + /* Reset the file indicator to the beginning of the file. */ + fseek(infile, 0L, SEEK_SET); + + /* Allocate a buffer for the file contents. */ + buffer = (uint8_t *)calloc(buffer_len, sizeof(uint8_t)); + if(buffer) + { + /* Read all the text from the file into the buffer. */ + fread(buffer, sizeof(uint8_t), buffer_len, infile); + printf("Read %zu bytes, fuzzing.. ", buffer_len); + + /* Call the fuzzer with the data. */ + LLVMFuzzerTestOneInput(buffer, buffer_len); + + printf("complete !!"); + + /* Free the buffer as it's no longer needed. */ + free(buffer); + buffer = NULL; + } + else + { + fprintf(stderr, + "[%s] Failed to allocate %zu bytes \n", + argv[ii], + buffer_len); + } + + /* Close the file as it's no longer needed. */ + fclose(infile); + infile = NULL; + } + else + { + /* Failed to open the file. Maybe wrong name or wrong permissions? */ + fprintf(stderr, "[%s] Open failed. \n", argv[ii]); + } + + printf("\n"); + } +} diff --git a/ossfuzz/testinput.h b/ossfuzz/testinput.h new file mode 100644 index 0000000..6ab9b51 --- /dev/null +++ b/ossfuzz/testinput.h @@ -0,0 +1,3 @@ +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); diff --git a/ossfuzz/travisoss.sh b/ossfuzz/travisoss.sh new file mode 100755 index 0000000..e99cc6e --- /dev/null +++ b/ossfuzz/travisoss.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -ex + +PROJECT_NAME=jansson + +# Clone the oss-fuzz repository +git clone https://github.com/google/oss-fuzz.git /tmp/ossfuzz + +if [[ ! -d /tmp/ossfuzz/projects/${PROJECT_NAME} ]] +then + echo "Could not find the ${PROJECT_NAME} project in ossfuzz" + + # Exit with a success code while the jansson project is not expected to exist + # on oss-fuzz. + exit 0 +fi + +# Modify the oss-fuzz Dockerfile so that we're checking out the current branch on travis. +sed -i "s@https://github.com/akheron/jansson.git@-b $TRAVIS_BRANCH https://github.com/akheron/jansson.git@" /tmp/ossfuzz/projects/${PROJECT_NAME}/Dockerfile + +# Try and build the fuzzers +pushd /tmp/ossfuzz +python infra/helper.py build_image --pull ${PROJECT_NAME} +python infra/helper.py build_fuzzers ${PROJECT_NAME} +popd From 24cc9dd0789d368861d750e0ebdda8747a0597d0 Mon Sep 17 00:00:00 2001 From: Max Dymond Date: Thu, 18 Jul 2019 14:49:07 +0100 Subject: [PATCH 2/2] Move ossfuzz directory and use Makefile.am --- .travis.yml | 2 +- Makefile.am | 12 ----- configure.ac | 15 ++++++ ossfuzz/json_load_fuzzer.cc | 11 ----- test/Makefile.am | 2 +- test/ossfuzz/.gitignore | 1 + test/ossfuzz/Makefile.am | 32 +++++++++++++ test/ossfuzz/json_load_dump_fuzzer.cc | 47 +++++++++++++++++++ {ossfuzz => test/ossfuzz}/ossfuzz.sh | 5 +- {ossfuzz => test/ossfuzz}/standaloneengine.cc | 0 {ossfuzz => test/ossfuzz}/testinput.h | 0 {ossfuzz => test/ossfuzz}/travisoss.sh | 0 12 files changed, 99 insertions(+), 28 deletions(-) delete mode 100644 ossfuzz/json_load_fuzzer.cc create mode 100644 test/ossfuzz/.gitignore create mode 100644 test/ossfuzz/Makefile.am create mode 100644 test/ossfuzz/json_load_dump_fuzzer.cc rename {ossfuzz => test/ossfuzz}/ossfuzz.sh (87%) rename {ossfuzz => test/ossfuzz}/standaloneengine.cc (100%) rename {ossfuzz => test/ossfuzz}/testinput.h (100%) rename {ossfuzz => test/ossfuzz}/travisoss.sh (100%) diff --git a/.travis.yml b/.travis.yml index 449e9bb..8dae9a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,4 +21,4 @@ script: - if [ "$JANSSON_BUILD_METHOD" = "autotools" ]; then autoreconf -f -i && CFLAGS=-Werror ./configure && make check; fi - if [ "$JANSSON_BUILD_METHOD" = "cmake" ]; then mkdir build && cd build && cmake $JANSSON_CMAKE_OPTIONS .. && cmake --build . && ctest --output-on-failure; fi - if [ "$JANSSON_BUILD_METHOD" = "coverage" ]; then mkdir build && cd build && cmake $JANSSON_CMAKE_OPTIONS .. && cmake --build . && cmake --build . --target coveralls; fi - - if [ "$JANSSON_BUILD_METHOD" = "fuzzer" ]; then ./ossfuzz/travisoss.sh; fi + - if [ "$JANSSON_BUILD_METHOD" = "fuzzer" ]; then ./test/ossfuzz/travisoss.sh; fi diff --git a/Makefile.am b/Makefile.am index 3e3dc09..0de2ac1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,15 +8,3 @@ dvi: pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = jansson.pc - - -# Add fuzzing support -LIB_FUZZING_ENGINE ?= standaloneengine.o - -ossfuzz/%.o: ossfuzz/%.cc - $(CXX) -c -Isrc $(CXXFLAGS) $< -o $@ - -.PHONY: json_load_fuzzer -json_load_fuzzer: ossfuzz/json_load_fuzzer.o src/.libs/libjansson.a - $(CXX) -c $(CXXFLAGS) ossfuzz/standaloneengine.cc -o standaloneengine.o - $(CXX) $(CXXFLAGS) $(LIB_FUZZING_ENGINE) $^ -o $@$(EXT) diff --git a/configure.ac b/configure.ac index cf9ac33..1e6500b 100644 --- a/configure.ac +++ b/configure.ac @@ -9,6 +9,7 @@ AC_CONFIG_HEADERS([jansson_private_config.h]) # Checks for programs. AC_PROG_CC +AC_PROG_CXX AC_PROG_LIBTOOL AM_CONDITIONAL([GCC], [test x$GCC = xyes]) @@ -136,6 +137,19 @@ fi AS_IF([test "x$with_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions]) AC_SUBST(JSON_BSYMBOLIC_LDFLAGS) + +AC_ARG_ENABLE([ossfuzzers], + [AS_HELP_STRING([--enable-ossfuzzers], + [Whether to generate the fuzzers for OSS-Fuzz])], + [have_ossfuzzers=yes], [have_ossfuzzers=no]) +AM_CONDITIONAL([USE_OSSFUZZERS], [test "x$have_ossfuzzers" = "xyes"]) + + +AC_SUBST([LIB_FUZZING_ENGINE]) +AM_CONDITIONAL([USE_OSSFUZZ_FLAG], [test "x$LIB_FUZZING_ENGINE" = "x-fsanitize=fuzzer"]) +AM_CONDITIONAL([USE_OSSFUZZ_STATIC], [test -f "x$LIB_FUZZING_ENGINE"]) + + if test x$GCC = xyes; then AC_MSG_CHECKING(for -Wno-format-truncation) wnoformat_truncation="-Wno-format-truncation" @@ -156,6 +170,7 @@ AC_CONFIG_FILES([ src/jansson_config.h test/Makefile test/bin/Makefile + test/ossfuzz/Makefile test/suites/Makefile test/suites/api/Makefile ]) diff --git a/ossfuzz/json_load_fuzzer.cc b/ossfuzz/json_load_fuzzer.cc deleted file mode 100644 index 09e7da5..0000000 --- a/ossfuzz/json_load_fuzzer.cc +++ /dev/null @@ -1,11 +0,0 @@ -#include - -#include "jansson.h" - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - json_error_t error; - auto jobj = json_loadb(reinterpret_cast(data), size, 0, &error); - if (jobj) - json_decref(jobj); - return 0; -} diff --git a/test/Makefile.am b/test/Makefile.am index 86d1614..344d18d 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = bin suites +SUBDIRS = bin suites ossfuzz EXTRA_DIST = scripts run-suites TESTS = run-suites diff --git a/test/ossfuzz/.gitignore b/test/ossfuzz/.gitignore new file mode 100644 index 0000000..7fbb867 --- /dev/null +++ b/test/ossfuzz/.gitignore @@ -0,0 +1 @@ +json_load_dump_fuzzer diff --git a/test/ossfuzz/Makefile.am b/test/ossfuzz/Makefile.am new file mode 100644 index 0000000..a2e802e --- /dev/null +++ b/test/ossfuzz/Makefile.am @@ -0,0 +1,32 @@ +AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src +LDADD = $(top_builddir)/src/libjansson.la + +if USE_OSSFUZZ_FLAG +FUZZ_FLAG = $(LIB_FUZZING_ENGINE) +else +if USE_OSSFUZZ_STATIC +LDADD += $(LIB_FUZZING_ENGINE) +FUZZ_FLAG = +else +LDADD += libstandaloneengine.a +FUZZ_FLAG = +endif +endif + +noinst_PROGRAMS = +noinst_LIBRARIES = + +if USE_OSSFUZZERS +noinst_PROGRAMS += \ + json_load_dump_fuzzer + +noinst_LIBRARIES += \ + libstandaloneengine.a +endif + +json_load_dump_fuzzer_SOURCES = json_load_dump_fuzzer.cc testinput.h +json_load_dump_fuzzer_CXXFLAGS = $(AM_CXXFLAGS) $(FUZZ_FLAG) +json_load_dump_fuzzer_LDFLAGS = $(AM_LDFLAGS) -static + +libstandaloneengine_a_SOURCES = standaloneengine.cc +libstandaloneengine_a_CXXFLAGS = $(AM_CXXFLAGS) diff --git a/test/ossfuzz/json_load_dump_fuzzer.cc b/test/ossfuzz/json_load_dump_fuzzer.cc new file mode 100644 index 0000000..09f52d2 --- /dev/null +++ b/test/ossfuzz/json_load_dump_fuzzer.cc @@ -0,0 +1,47 @@ +#include +#include + +#include "jansson.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + json_error_t error; + + if (size < sizeof(size_t) + sizeof(size_t)) + { + return 0; + } + + // Use the first sizeof(size_t) bytes as load flags. + size_t load_flags = *(const size_t*)data; + data += sizeof(size_t); + size -= sizeof(size_t); + + // Use the next sizeof(size_t) bytes as dump flags. + size_t dump_flags = *(const size_t*)data; + data += sizeof(size_t); + size -= sizeof(size_t); + + // Attempt to load the remainder of the data with the given load flags. + const char* text = reinterpret_cast(data); + json_t* jobj = json_loadb(text, size, load_flags, &error); + + if (jobj == NULL) + { + return 0; + } + + // Attempt to dump the loaded json object with the given dump flags. + char* out = json_dumps(jobj, dump_flags); + if (out) + { + free(out); + } + + if (jobj) + { + json_decref(jobj); + } + + return 0; +} \ No newline at end of file diff --git a/ossfuzz/ossfuzz.sh b/test/ossfuzz/ossfuzz.sh similarity index 87% rename from ossfuzz/ossfuzz.sh rename to test/ossfuzz/ossfuzz.sh index 897e5a6..9d72e79 100755 --- a/ossfuzz/ossfuzz.sh +++ b/test/ossfuzz/ossfuzz.sh @@ -20,9 +20,8 @@ apt-get -y install automake libtool # Compile the fuzzer. autoreconf -i -./configure +./configure --enable-ossfuzzers make -make json_load_fuzzer # Copy the fuzzer to the output directory. -cp -v json_load_fuzzer $OUT/ +cp -v test/ossfuzz/json_load_dump_fuzzer $OUT/ diff --git a/ossfuzz/standaloneengine.cc b/test/ossfuzz/standaloneengine.cc similarity index 100% rename from ossfuzz/standaloneengine.cc rename to test/ossfuzz/standaloneengine.cc diff --git a/ossfuzz/testinput.h b/test/ossfuzz/testinput.h similarity index 100% rename from ossfuzz/testinput.h rename to test/ossfuzz/testinput.h diff --git a/ossfuzz/travisoss.sh b/test/ossfuzz/travisoss.sh similarity index 100% rename from ossfuzz/travisoss.sh rename to test/ossfuzz/travisoss.sh