diff --git a/.gitignore b/.gitignore index 38c414e0f..e567b38c4 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,4 @@ test-driver scripts/_curl curl_fuzzer curl_fuzzer_seed_corpus.zip +libstandaloneengine.a diff --git a/.travis.yml b/.travis.yml index cd8876e86..ca5ea8eba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -145,7 +145,12 @@ script: - | if [ "$T" = "fuzzer" ]; then export CC=clang + export CXX=clang++ export CFLAGS="-fsanitize=address" + + # Specifically use libstdc++ for travis as libc++ is not installed. + # This is ok because we're not compiling against libFuzzer. + export CXXFLAGS="-fsanitize=address -stdlib=libstdc++" ./configure --disable-shared --enable-debug --enable-maintainer-mode make cd tests/fuzz diff --git a/configure.ac b/configure.ac index 04d92d8f4..27d560f83 100755 --- a/configure.ac +++ b/configure.ac @@ -52,6 +52,7 @@ CURL_CHECK_OPTION_RT XC_CHECK_PATH_SEPARATOR AX_CODE_COVERAGE +AC_PROG_CXX # # save the configure arguments diff --git a/tests/fuzz/Makefile.am b/tests/fuzz/Makefile.am index 270b9783e..b7968d3d4 100644 --- a/tests/fuzz/Makefile.am +++ b/tests/fuzz/Makefile.am @@ -30,12 +30,12 @@ AUTOMAKE_OPTIONS = foreign nostdinc # $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file # $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "borrowed" files -AM_CFLAGS = -I$(top_srcdir)/include \ - -I$(top_builddir)/lib \ - -I$(top_srcdir)/lib \ - -I$(top_srcdir)/tests/fuzz +AM_CXXFLAGS = -I$(top_srcdir)/include \ + -I$(top_builddir)/lib \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/tests/fuzz -LIBS = -lpthread -lstdc++ -lm +LIBS = -lpthread -lm # Run e.g. "make all LIB_FUZZING_ENGINE=/path/to/libFuzzer.a" # to link the fuzzer(s) against a real fuzzing engine. @@ -53,4 +53,4 @@ checksrc: @PERL@ $(top_srcdir)/lib/checksrc.pl $(srcdir)/*.c noinst_PROGRAMS = $(FUZZPROGS) -noinst_LIBRARIES = $(FUZZLIBS) \ No newline at end of file +noinst_LIBRARIES = $(FUZZLIBS) diff --git a/tests/fuzz/Makefile.inc b/tests/fuzz/Makefile.inc index 4d475374b..f52adb89c 100644 --- a/tests/fuzz/Makefile.inc +++ b/tests/fuzz/Makefile.inc @@ -1,15 +1,15 @@ FUZZPROGS = curl_fuzzer FUZZLIBS = libstandaloneengine.a -curl_fuzzer_SOURCES = curl_fuzzer.c -curl_fuzzer_CFLAGS = $(AM_CFLAGS) +curl_fuzzer_SOURCES = curl_fuzzer.cc +curl_fuzzer_CXXFLAGS = $(AM_CXXFLAGS) -libstandaloneengine_a_SOURCES = standalone_fuzz_target_runner.c -libstandaloneengine_a_CFLAGS = $(AM_CFLAGS) +libstandaloneengine_a_SOURCES = standalone_fuzz_target_runner.cc +libstandaloneengine_a_CXXFLAGS = $(AM_CXXFLAGS) # Some more targets. zip: zip -q -r curl_fuzzer_seed_corpus.zip curl_fuzz_data check: all - ./curl_fuzzer curl_fuzz_data/* \ No newline at end of file + ./curl_fuzzer curl_fuzz_data/* diff --git a/tests/fuzz/README b/tests/fuzz/README index cdb69fe82..8b5fcd011 100644 --- a/tests/fuzz/README +++ b/tests/fuzz/README @@ -8,7 +8,9 @@ Building the fuzz target From the CURL root directory: export CC=clang-5.0 +export CXX=clang++-5.0 export CFLAGS="-fsanitize=address -fsanitize-address-use-after-scope -fsanitize-coverage=trace-pc-guard,trace-cmp" +export CXXFLAGS="-fsanitize=address -fsanitize-address-use-after-scope -fsanitize-coverage=trace-pc-guard,trace-cmp -stdlib=libc++" ./configure --disable-shared --enable-debug --enable-maintainer-mode make -sj diff --git a/tests/fuzz/curl_fuzzer.c b/tests/fuzz/curl_fuzzer.cc similarity index 96% rename from tests/fuzz/curl_fuzzer.c rename to tests/fuzz/curl_fuzzer.cc index f4a4ec6f9..92bedf92e 100644 --- a/tests/fuzz/curl_fuzzer.c +++ b/tests/fuzz/curl_fuzzer.cc @@ -32,15 +32,18 @@ * Fuzzing entry point. This function is passed a buffer containing a test * case. This test case should drive the CURL API into making a request. */ -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { int rc = 0; int tlv_rc; FUZZ_DATA fuzz; TLV tlv; + /* Have to set all fields to zero before getting to the terminate function */ + memset(&fuzz, 0, sizeof(FUZZ_DATA)); + if(size < sizeof(TLV_RAW)) { - /* Not enough data */ + /* Not enough data for a single TLV - don't continue */ goto EXIT_LABEL; } @@ -329,7 +332,7 @@ char *fuzz_tlv_to_string(TLV *tlv) char *tlvstr; /* Allocate enough space, plus a null terminator */ - tlvstr = malloc(tlv->length + 1); + tlvstr = (char *)malloc(tlv->length + 1); if(tlvstr != NULL) { memcpy(tlvstr, tlv->value, tlv->length); diff --git a/tests/fuzz/curl_fuzzer.h b/tests/fuzz/curl_fuzzer.h index a0c9d596a..634160648 100644 --- a/tests/fuzz/curl_fuzzer.h +++ b/tests/fuzz/curl_fuzzer.h @@ -21,6 +21,7 @@ ***************************************************************************/ #include +#include /** * TLV types. @@ -107,7 +108,6 @@ typedef struct fuzz_data } FUZZ_DATA; /* Function prototypes */ -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); uint32_t to_u32(uint8_t b[4]); uint16_t to_u16(uint8_t b[2]); int fuzz_initialize_fuzz_data(FUZZ_DATA *fuzz, diff --git a/tests/fuzz/standalone_fuzz_target_runner.c b/tests/fuzz/standalone_fuzz_target_runner.cc similarity index 98% rename from tests/fuzz/standalone_fuzz_target_runner.c rename to tests/fuzz/standalone_fuzz_target_runner.cc index c131a2192..9b2316ed6 100644 --- a/tests/fuzz/standalone_fuzz_target_runner.c +++ b/tests/fuzz/standalone_fuzz_target_runner.cc @@ -24,7 +24,7 @@ #include #include -#include "standalone_fuzz_target_runner.h" +#include "testinput.h" /** * Main procedure for standalone fuzzing engine. diff --git a/tests/fuzz/standalone_fuzz_target_runner.h b/tests/fuzz/testinput.h similarity index 93% rename from tests/fuzz/standalone_fuzz_target_runner.h rename to tests/fuzz/testinput.h index 37302618b..0746cba73 100644 --- a/tests/fuzz/standalone_fuzz_target_runner.h +++ b/tests/fuzz/testinput.h @@ -20,4 +20,4 @@ * ***************************************************************************/ -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); \ No newline at end of file +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); \ No newline at end of file