From 48e4099ad2427fcdd6da2e23e00ea3d98eb5bf2e Mon Sep 17 00:00:00 2001 From: Mikhail Khachayants Date: Sun, 20 Oct 2024 14:33:37 +0300 Subject: [PATCH] Fuzzing improvements --- tests/fuzzing/fuzzer.cpp | 97 ++++++++++++++++++++++----------- tests/fuzzing/oss-fuzz-build.sh | 37 +++++-------- 2 files changed, 81 insertions(+), 53 deletions(-) diff --git a/tests/fuzzing/fuzzer.cpp b/tests/fuzzing/fuzzer.cpp index 7baeddb..6cafc64 100644 --- a/tests/fuzzing/fuzzer.cpp +++ b/tests/fuzzing/fuzzer.cpp @@ -1,43 +1,78 @@ -#include -#include - -#include #include -#include -#include #include +#include using valijson::Schema; using valijson::SchemaParser; +using valijson::ValidationResults; +using valijson::Validator; +using valijson::adapters::AdapterTraits; using valijson::adapters::RapidJsonAdapter; +using AdapterType = RapidJsonAdapter; -extern "C" int -LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +void runOneTest(const AdapterType &test, const Schema &schema, + Validator::TypeCheckingMode mode) { - if(size<3) return 0; - char input_file[256]; - sprintf(input_file, "/tmp/libfuzzer.json"); - FILE *fp = fopen(input_file, "wb"); - if (!fp) - return 0; - fwrite(data, size, 1, fp); - fclose(fp); - - rapidjson::Document schemaDocument; - if (!valijson::utils::loadDocument(input_file, schemaDocument)) { - return 1; - } - - Schema schema; - SchemaParser parser; - RapidJsonAdapter schemaDocumentAdapter(schemaDocument); try { - parser.populateSchema(schemaDocumentAdapter, schema); - } catch (std::exception &e) { - unlink(input_file); - return 1; + if (!test.isObject()) { + return; + } + + const AdapterType::Object testObject = test.getObject(); + const auto dataItr = testObject.find("data"); + + if (dataItr == testObject.end()) { + return; + } + + Validator validator(mode); + ValidationResults results; + validator.validate(schema, dataItr->second, &results); + } catch (const std::exception &) { + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + AdapterTraits::DocumentType document; + document.template Parse(reinterpret_cast(data), size); + + if (document.HasParseError() || !document.IsArray()) { + return 0; } - unlink(input_file); - return 1; + for (const auto &testCase : AdapterType(document).getArray()) { + if (!testCase.isObject()) { + continue; + } + + const AdapterType::Object object = testCase.getObject(); + const auto schemaItr = object.find("schema"); + const auto testsItr = object.find("tests"); + + if (schemaItr == object.end() || testsItr == object.end() || + !testsItr->second.isArray()) { + continue; + } + + Schema schema; + SchemaParser parser(size % 2 ? SchemaParser::kDraft4 + : SchemaParser::kDraft7); + + try { + parser.populateSchema(schemaItr->second, schema); + } catch (const std::exception &) { + continue; + } + + const auto mode = testsItr->second.hasStrictTypes() + ? Validator::kStrongTypes + : Validator::kWeakTypes; + + for (const AdapterType test : testsItr->second.getArray()) { + runOneTest(test, schema, mode); + } + } + + return 0; } diff --git a/tests/fuzzing/oss-fuzz-build.sh b/tests/fuzzing/oss-fuzz-build.sh index 8fd7233..be9757c 100755 --- a/tests/fuzzing/oss-fuzz-build.sh +++ b/tests/fuzzing/oss-fuzz-build.sh @@ -2,38 +2,31 @@ git submodule update --init --depth 1 thirdparty -# This line causes an abort which breaks fuzzing: -sed -i '27d' include/valijson/utils/rapidjson_utils.hpp - mkdir build cd build cmake \ - -Dvalijson_BUILD_TESTS=TRUE \ + -Dvalijson_BUILD_TESTS=FALSE \ -Dvalijson_BUILD_EXAMPLES=FALSE \ - -Dvalijson_EXCLUDE_BOOST=TRUE \ - .. + -Dvalijson_EXCLUDE_BOOST=TRUE \ + .. make -j"$(nproc)" cd ../tests/fuzzing -find ../.. -name "*.o" -exec ar rcs fuzz_lib.a {} \; - # CXXFLAGS may contain spaces -# shellcheck disable=SC2086 -"$CXX" $CXXFLAGS -DVALIJSON_USE_EXCEPTIONS=1 \ - -I/src/valijson/thirdparty/rapidjson/include \ - -I/src/valijson/thirdparty/rapidjson/include/rapidjson \ - -I/src/valijson/include \ - -I/src/valijson/include/valijson \ - -I/src/valijson/include/valijson/adapters \ - -c fuzzer.cpp -o fuzzer.o - # shellcheck disable=SC2086 "$CXX" $CXXFLAGS "$LIB_FUZZING_ENGINE" \ - -DVALIJSON_USE_EXCEPTIONS=1 \ - -rdynamic fuzzer.o \ - -o "${OUT}/fuzzer" fuzz_lib.a + -DVALIJSON_USE_EXCEPTIONS=1 \ + -I/src/valijson/thirdparty/rapidjson/include \ + -I/src/valijson/include \ + fuzzer.cpp -o "${OUT}/fuzzer" -zip "${OUT}/fuzzer_seed_corpus.zip" \ - "${SRC}/valijson/doc/schema/draft-03.json" +mkdir seed_corpus + +find "${SRC}/valijson/thirdparty/JSON-Schema-Test-Suite/tests" -name "*.json" | while read file; do + sha1=$(sha1sum "$file" | awk '{print $1}') + cp "$file" seed_corpus/"${sha1}" +done + +zip -j -r "${OUT}/fuzzer_seed_corpus.zip" seed_corpus