From f7f175fdf298b644efdd43e38be66608c13ccdb6 Mon Sep 17 00:00:00 2001 From: Randy Date: Thu, 11 Jul 2019 13:56:07 +0200 Subject: [PATCH 1/7] add fuzz target --- fuzzing/cjson_read_fuzzer.cc | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 fuzzing/cjson_read_fuzzer.cc diff --git a/fuzzing/cjson_read_fuzzer.cc b/fuzzing/cjson_read_fuzzer.cc new file mode 100644 index 0000000..d7af5c2 --- /dev/null +++ b/fuzzing/cjson_read_fuzzer.cc @@ -0,0 +1,41 @@ +#include +#include + +#include "../cJSON.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + if((data[0] == '\0') || (size < 3) || (data[1] == '\0')) return 0; + + cJSON *json = cJSON_Parse((const char*)data + 2); + + if(json == NULL) return 0; + + int do_format = 0; + char *printed_json = NULL; + + if(data[1] == 'f') do_format = 1; + + if(data[0] == 'b') + { + /* buffered printing */ + printed_json = cJSON_PrintBuffered(json, 1, do_format); + } + else + { + /* unbuffered printing */ + if(do_format) + { + printed_json = cJSON_Print(json); + } + else + { + printed_json = cJSON_PrintUnformatted(json); + } + } + + if(printed_json != NULL) free(printed_json); + cJSON_Delete(json); + + return 0; +} From 2691e142f4a881b470e7d5e889ef4ca4a589cadf Mon Sep 17 00:00:00 2001 From: Randy Date: Thu, 11 Jul 2019 14:42:27 +0200 Subject: [PATCH 2/7] update fuzzer --- fuzzing/cjson_read_fuzzer.cc | 38 +++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/fuzzing/cjson_read_fuzzer.cc b/fuzzing/cjson_read_fuzzer.cc index d7af5c2..be2fe67 100644 --- a/fuzzing/cjson_read_fuzzer.cc +++ b/fuzzing/cjson_read_fuzzer.cc @@ -1,30 +1,38 @@ #include #include +#include #include "../cJSON.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - if((data[0] == '\0') || (size < 3) || (data[1] == '\0')) return 0; + size_t offset = 4; - cJSON *json = cJSON_Parse((const char*)data + 2); + if(size < offset) return 0; + if(data[0] != '1' && data[0] != '0') return 0; + if(data[1] != '1' && data[1] != '0') return 0; + if(data[2] != '1' && data[2] != '0') return 0; + if(data[3] != '1' && data[3] != '0') return 0; + + int minify = data[0] == '1' ? 1 : 0; + int require_termination = data[1] == '1' ? 1 : 0; + int formatted = data[2] == '1' ? 1 : 0; + int buffered = data[3] == '1' ? 1 : 0; + + cJSON *json = cJSON_ParseWithOpts((const char*)data + offset, NULL, require_termination); if(json == NULL) return 0; - int do_format = 0; char *printed_json = NULL; - if(data[1] == 'f') do_format = 1; - - if(data[0] == 'b') + if(buffered) { - /* buffered printing */ - printed_json = cJSON_PrintBuffered(json, 1, do_format); + printed_json = cJSON_PrintBuffered(json, 1, formatted); } else { /* unbuffered printing */ - if(do_format) + if(formatted) { printed_json = cJSON_Print(json); } @@ -35,6 +43,18 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) } if(printed_json != NULL) free(printed_json); + + if(minify) + { + unsigned char *copied = (unsigned char*)malloc(size); + + memcpy(copied, data + offset, size); + + cJSON_Minify((char*)printed_json); + free(copied); + } + + cJSON_Delete(json); return 0; From e6bc5d16e6e1c336523fbda6493c4f7ee3863415 Mon Sep 17 00:00:00 2001 From: Randy Date: Thu, 11 Jul 2019 15:03:04 +0200 Subject: [PATCH 3/7] update fuzzer --- fuzzing/cjson_read_fuzzer.cc | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/fuzzing/cjson_read_fuzzer.cc b/fuzzing/cjson_read_fuzzer.cc index be2fe67..57cbd0c 100644 --- a/fuzzing/cjson_read_fuzzer.cc +++ b/fuzzing/cjson_read_fuzzer.cc @@ -19,9 +19,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) int formatted = data[2] == '1' ? 1 : 0; int buffered = data[3] == '1' ? 1 : 0; - cJSON *json = cJSON_ParseWithOpts((const char*)data + offset, NULL, require_termination); + unsigned char *copied = (unsigned char*)malloc(size); + if(copied == NULL) return 0; - if(json == NULL) return 0; + memcpy(copied, data, size); + copied[size-1] = '\0'; + + cJSON *json = cJSON_ParseWithOpts((const char*)copied + offset, NULL, require_termination); + + if(json == NULL) + { + free(copied); + return 0; + } char *printed_json = NULL; @@ -46,16 +56,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) if(minify) { - unsigned char *copied = (unsigned char*)malloc(size); - - memcpy(copied, data + offset, size); - - cJSON_Minify((char*)printed_json); - free(copied); + cJSON_Minify((char*)copied + offset); } - cJSON_Delete(json); + free(copied); return 0; } From 2d6db59c7bddee0f052b5ed511bcfd4306badaa9 Mon Sep 17 00:00:00 2001 From: Randy Date: Thu, 11 Jul 2019 15:09:10 +0200 Subject: [PATCH 4/7] update fuzzer --- fuzzing/cjson_read_fuzzer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzing/cjson_read_fuzzer.cc b/fuzzing/cjson_read_fuzzer.cc index 57cbd0c..3b76894 100644 --- a/fuzzing/cjson_read_fuzzer.cc +++ b/fuzzing/cjson_read_fuzzer.cc @@ -8,7 +8,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { size_t offset = 4; - if(size < offset) return 0; + if(size <= offset) return 0; if(data[0] != '1' && data[0] != '0') return 0; if(data[1] != '1' && data[1] != '0') return 0; if(data[2] != '1' && data[2] != '0') return 0; From bd1a375028a29f2ee39a96ac8459b8ea4711ed0a Mon Sep 17 00:00:00 2001 From: Randy Date: Sat, 24 Aug 2019 17:42:48 +0200 Subject: [PATCH 5/7] add fuzzer driver, integrate with build system --- fuzzing/CMakeLists.txt | 5 ++++ fuzzing/cjson_read_fuzzer.cc | 24 ++++++++++------ fuzzing/fuzz_main.c | 56 ++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 fuzzing/fuzz_main.c diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index fdd7126..84278e8 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -26,3 +26,8 @@ if (ENABLE_FUZZING) endif() + +if(ENABLE_CJSON_TEST) + ADD_EXECUTABLE(fuzz_main fuzz_main.c) + TARGET_LINK_LIBRARIES(fuzz_main cjson) +endif() \ No newline at end of file diff --git a/fuzzing/cjson_read_fuzzer.cc b/fuzzing/cjson_read_fuzzer.cc index 3b76894..4ec4322 100644 --- a/fuzzing/cjson_read_fuzzer.cc +++ b/fuzzing/cjson_read_fuzzer.cc @@ -4,9 +4,17 @@ #include "../cJSON.h" -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +#ifdef __cplusplus +extern "C" +#endif +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + cJSON *json; size_t offset = 4; + unsigned char *copied; + char *printed_json = NULL; + int minify, require_termination, formatted, buffered; + if(size <= offset) return 0; if(data[0] != '1' && data[0] != '0') return 0; @@ -14,18 +22,18 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) if(data[2] != '1' && data[2] != '0') return 0; if(data[3] != '1' && data[3] != '0') return 0; - int minify = data[0] == '1' ? 1 : 0; - int require_termination = data[1] == '1' ? 1 : 0; - int formatted = data[2] == '1' ? 1 : 0; - int buffered = data[3] == '1' ? 1 : 0; + minify = data[0] == '1' ? 1 : 0; + require_termination = data[1] == '1' ? 1 : 0; + formatted = data[2] == '1' ? 1 : 0; + buffered = data[3] == '1' ? 1 : 0; - unsigned char *copied = (unsigned char*)malloc(size); + copied = (unsigned char*)malloc(size); if(copied == NULL) return 0; memcpy(copied, data, size); copied[size-1] = '\0'; - cJSON *json = cJSON_ParseWithOpts((const char*)copied + offset, NULL, require_termination); + json = cJSON_ParseWithOpts((const char*)copied + offset, NULL, require_termination); if(json == NULL) { @@ -33,8 +41,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) return 0; } - char *printed_json = NULL; - if(buffered) { printed_json = cJSON_PrintBuffered(json, 1, formatted); diff --git a/fuzzing/fuzz_main.c b/fuzzing/fuzz_main.c new file mode 100644 index 0000000..e004115 --- /dev/null +++ b/fuzzing/fuzz_main.c @@ -0,0 +1,56 @@ +#include +#include +#include + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C90 */ + +#include "cjson_read_fuzzer.cc" + +/* fuzz target entry point, works without libFuzzer */ + +int main(int argc, char **argv) +{ + FILE *f; + char *buf = NULL; + long siz_buf; + + if(argc < 2) + { + fprintf(stderr, "no input file\n"); + goto err; + } + + f = fopen(argv[1], "rb"); + if(f == NULL) + { + fprintf(stderr, "error opening input file %s\n", argv[1]); + goto err; + } + + fseek(f, 0, SEEK_END); + + siz_buf = ftell(f); + rewind(f); + + if(siz_buf < 1) goto err; + + buf = (char*)malloc((size_t)siz_buf); + if(buf == NULL) + { + fprintf(stderr, "malloc() failed\n"); + goto err; + } + + if(fread(buf, (size_t)siz_buf, 1, f) != 1) + { + fprintf(stderr, "fread() failed\n"); + goto err; + } + + (void)LLVMFuzzerTestOneInput((uint8_t*)buf, (size_t)siz_buf); + +err: + free(buf); + + return 0; +} From dc56e24f7f1d3ffc72e8b5a0039c6137b43e89d4 Mon Sep 17 00:00:00 2001 From: randy408 Date: Mon, 14 Oct 2019 17:12:13 +0200 Subject: [PATCH 6/7] add build script --- fuzzing/ossfuzz.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 fuzzing/ossfuzz.sh diff --git a/fuzzing/ossfuzz.sh b/fuzzing/ossfuzz.sh new file mode 100644 index 0000000..8de60e4 --- /dev/null +++ b/fuzzing/ossfuzz.sh @@ -0,0 +1,19 @@ +#!/bin/bash -eu + +# This script is meant to be run by +# https://github.com/google/oss-fuzz/blob/master/projects/cjson/Dockerfile + +mkdir build +cd build +cmake -DBUILD_SHARED_LIBS=OFF -DENABLE_CJSON_TEST=OFF .. +make -j$(nproc) + +$CXX $CXXFLAGS -std=c++11 -I. \ + $SRC/cjson/fuzzing/cjson_read_fuzzer.cc \ + -o $OUT/cjson_read_fuzzer \ + $LIB_FUZZING_ENGINE $SRC/cjson/build/libcjson.a + +find $SRC/cjson/fuzzing/inputs -name "*" | \ + xargs zip $OUT/cjson_read_fuzzer_seed_corpus.zip + +cp $SRC/cjson/fuzzing/json.dict $OUT/cjson_read_fuzzer.dict From ec8d2f9c2e9de7524f9ddd78d39605d5fc6987ef Mon Sep 17 00:00:00 2001 From: randy408 Date: Mon, 21 Oct 2019 15:27:47 +0200 Subject: [PATCH 7/7] convert fuzz target to c89, optimize --- fuzzing/CMakeLists.txt | 2 +- ...son_read_fuzzer.cc => cjson_read_fuzzer.c} | 28 ++++++++----------- fuzzing/fuzz_main.c | 4 +-- fuzzing/ossfuzz.sh | 4 +-- 4 files changed, 16 insertions(+), 22 deletions(-) rename fuzzing/{cjson_read_fuzzer.cc => cjson_read_fuzzer.c} (77%) diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index 84278e8..587368d 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -28,6 +28,6 @@ if (ENABLE_FUZZING) endif() if(ENABLE_CJSON_TEST) - ADD_EXECUTABLE(fuzz_main fuzz_main.c) + ADD_EXECUTABLE(fuzz_main fuzz_main.c cjson_read_fuzzer.c) TARGET_LINK_LIBRARIES(fuzz_main cjson) endif() \ No newline at end of file diff --git a/fuzzing/cjson_read_fuzzer.cc b/fuzzing/cjson_read_fuzzer.c similarity index 77% rename from fuzzing/cjson_read_fuzzer.cc rename to fuzzing/cjson_read_fuzzer.c index 4ec4322..b2692ed 100644 --- a/fuzzing/cjson_read_fuzzer.cc +++ b/fuzzing/cjson_read_fuzzer.c @@ -4,9 +4,8 @@ #include "../cJSON.h" -#ifdef __cplusplus -extern "C" -#endif +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C89 */ + int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { cJSON *json; @@ -17,6 +16,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) if(size <= offset) return 0; + if(data[size-1] != '\0') return 0; if(data[0] != '1' && data[0] != '0') return 0; if(data[1] != '1' && data[1] != '0') return 0; if(data[2] != '1' && data[2] != '0') return 0; @@ -27,19 +27,9 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) formatted = data[2] == '1' ? 1 : 0; buffered = data[3] == '1' ? 1 : 0; - copied = (unsigned char*)malloc(size); - if(copied == NULL) return 0; + json = cJSON_ParseWithOpts((const char*)data + offset, NULL, require_termination); - memcpy(copied, data, size); - copied[size-1] = '\0'; - - json = cJSON_ParseWithOpts((const char*)copied + offset, NULL, require_termination); - - if(json == NULL) - { - free(copied); - return 0; - } + if(json == NULL) return 0; if(buffered) { @@ -62,11 +52,17 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) if(minify) { + copied = (unsigned char*)malloc(size); + if(copied == NULL) return 0; + + memcpy(copied, data, size); + cJSON_Minify((char*)copied + offset); + + free(copied); } cJSON_Delete(json); - free(copied); return 0; } diff --git a/fuzzing/fuzz_main.c b/fuzzing/fuzz_main.c index e004115..09dc156 100644 --- a/fuzzing/fuzz_main.c +++ b/fuzzing/fuzz_main.c @@ -2,9 +2,7 @@ #include #include -int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C90 */ - -#include "cjson_read_fuzzer.cc" +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C89 */ /* fuzz target entry point, works without libFuzzer */ diff --git a/fuzzing/ossfuzz.sh b/fuzzing/ossfuzz.sh index 8de60e4..fe4bf16 100644 --- a/fuzzing/ossfuzz.sh +++ b/fuzzing/ossfuzz.sh @@ -8,8 +8,8 @@ cd build cmake -DBUILD_SHARED_LIBS=OFF -DENABLE_CJSON_TEST=OFF .. make -j$(nproc) -$CXX $CXXFLAGS -std=c++11 -I. \ - $SRC/cjson/fuzzing/cjson_read_fuzzer.cc \ +$CC $CFLAGS -std=c89 -I. \ + $SRC/cjson/fuzzing/cjson_read_fuzzer.c \ -o $OUT/cjson_read_fuzzer \ $LIB_FUZZING_ENGINE $SRC/cjson/build/libcjson.a