diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index fdd7126e98684ce7c88906ac5bdadaa903af15cf..587368d066c539eaa527654499c2fab9bb98f008 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 cjson_read_fuzzer.c) + TARGET_LINK_LIBRARIES(fuzz_main cjson) +endif() \ No newline at end of file diff --git a/fuzzing/cjson_read_fuzzer.c b/fuzzing/cjson_read_fuzzer.c new file mode 100644 index 0000000000000000000000000000000000000000..b2692eddb35416726fe6f8c44f7646783de2d8c1 --- /dev/null +++ b/fuzzing/cjson_read_fuzzer.c @@ -0,0 +1,68 @@ +#include +#include +#include + +#include "../cJSON.h" + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C89 */ + +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[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; + if(data[3] != '1' && data[3] != '0') return 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; + + json = cJSON_ParseWithOpts((const char*)data + offset, NULL, require_termination); + + if(json == NULL) return 0; + + if(buffered) + { + printed_json = cJSON_PrintBuffered(json, 1, formatted); + } + else + { + /* unbuffered printing */ + if(formatted) + { + printed_json = cJSON_Print(json); + } + else + { + printed_json = cJSON_PrintUnformatted(json); + } + } + + if(printed_json != NULL) free(printed_json); + + 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); + + return 0; +} diff --git a/fuzzing/fuzz_main.c b/fuzzing/fuzz_main.c new file mode 100644 index 0000000000000000000000000000000000000000..09dc15652af57c1dd2b0208192459d5b753e3a74 --- /dev/null +++ b/fuzzing/fuzz_main.c @@ -0,0 +1,54 @@ +#include +#include +#include + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C89 */ + +/* 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; +} diff --git a/fuzzing/ossfuzz.sh b/fuzzing/ossfuzz.sh new file mode 100644 index 0000000000000000000000000000000000000000..fe4bf1601de1d35aec9a4fd08a896cd3e099a8fe --- /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) + +$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 + +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