From 1a4cbd495aa80965ee343acfe9f9b7abef3670a3 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Wed, 20 Jul 2022 16:48:23 +0200 Subject: [PATCH 01/36] fuzzers: Add a new libprotobuf-mutator fuzzer. This fuzzer provides significantly higher coverage of the library, as it implements more handlers and supports parser suspend/resume/reset and external entity parsing. --- expat/CMakeLists.txt | 46 ++++ expat/fuzz/xml_lpm_fuzzer.cpp | 395 ++++++++++++++++++++++++++++++++ expat/fuzz/xml_lpm_fuzzer.proto | 56 +++++ 3 files changed, 497 insertions(+) create mode 100644 expat/fuzz/xml_lpm_fuzzer.cpp create mode 100644 expat/fuzz/xml_lpm_fuzzer.proto diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index 85cdff45..09264a3e 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -669,6 +669,52 @@ if(EXPAT_BUILD_FUZZERS) TARGET ${target_name} PROPERTY RUNTIME_OUTPUT_DIRECTORY fuzz) endforeach() endforeach() + + find_package(Protobuf REQUIRED) + + # Only include libprotobuf-mutator here so we don't build it in non-fuzz + # configurations. + include(ExternalProject) + + set(ProtobufMutator_PREFIX libprotobuf-mutator) + set(ProtobufMutator_PATH ${CMAKE_CURRENT_BINARY_DIR}/${ProtobufMutator_PREFIX}/src/${ProtobufMutator_PREFIX}) + set(ProtobufMutator_BUILD_PATH ${ProtobufMutator_PATH}-build) + set(ProtobufMutator_INCLUDE_DIR ${ProtobufMutator_PATH}) + set(ProtobufMutator_LIBRARIES ${ProtobufMutator_BUILD_PATH}/src/libfuzzer/libprotobuf-mutator-libfuzzer.a ${ProtobufMutator_BUILD_PATH}/src/libprotobuf-mutator.a) + + ExternalProject_Add( + ${ProtobufMutator_PREFIX} + PREFIX ${ProtobufMutator_PREFIX} + GIT_REPOSITORY https://github.com/google/libprotobuf-mutator.git + GIT_TAG master + CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} + BUILD_BYPRODUCTS ${ProtobufMutator_LIBRARIES} + UPDATE_COMMAND true + INSTALL_COMMAND true) + + protobuf_generate_cpp(XML_LPM_FUZZER_PROTO_SRCS + XML_LPM_FUZZER_PROTO_HDRS + fuzz/xml_lpm_fuzzer.proto) + + add_executable(xml_lpm_fuzzer + fuzz/xml_lpm_fuzzer.cpp + ${XML_LPM_FUZZER_PROTO_SRCS}) + set_target_properties(xml_lpm_fuzzer PROPERTIES LINKER_LANGUAGE CXX) + target_include_directories(xml_lpm_fuzzer PUBLIC ${ProtobufMutator_INCLUDE_DIR}) + target_link_libraries(xml_lpm_fuzzer + fuzzpat + ${Protobuf_LIBRARIES} + ${ProtobufMutator_LIBRARIES}) + # NOTE: Avoiding target_link_options here only because it needs CMake >=3.13 + if(EXPAT_OSSFUZZ_BUILD) + set_target_properties(xml_lpm_fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) + set_target_properties(xml_lpm_fuzzer PROPERTIES LINKER_LANGUAGE "CXX") + else() + target_compile_options(xml_lpm_fuzzer PRIVATE -fsanitize=fuzzer-no-link) + set_target_properties(xml_lpm_fuzzer PROPERTIES LINK_FLAGS -fsanitize=fuzzer) + endif() + set_property(TARGET xml_lpm_fuzzer PROPERTY RUNTIME_OUTPUT_DIRECTORY fuzz) else() if(EXPAT_OSSFUZZ_BUILD) message(SEND_ERROR diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp new file mode 100644 index 00000000..9dde59f3 --- /dev/null +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -0,0 +1,395 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 2022 Google LLC + Licensed under the MIT license: + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include + +#include "expat.h" +#include "xml_lpm_fuzzer.pb.h" +#include "src/libfuzzer/libfuzzer_macro.h" + +static const char* encoding = nullptr; +static const char* external_entity = nullptr; +static size_t external_entity_size = 0; + +void SetEncoding(const xml_lpm_fuzzer::Encoding& e) { + switch (e) { + case xml_lpm_fuzzer::Encoding::UTF8: + encoding = "UTF-8"; + break; + + case xml_lpm_fuzzer::Encoding::UTF16: + encoding = "UTF-16"; + break; + + case xml_lpm_fuzzer::Encoding::ISO88591: + encoding = "ISO-8859-1"; + break; + + case xml_lpm_fuzzer::Encoding::ASCII: + encoding = "US-ASCII"; + break; + + case xml_lpm_fuzzer::Encoding::NONE: + encoding = NULL; + break; + + default: + encoding = "UNKNOWN"; + break; + } +} + +void InitializeParser(XML_Parser parser); + +// We want a parse function that supports resumption, so that we can cover the +// suspend/resume code. +enum XML_Status Parse(XML_Parser parser, const XML_Char* input, int input_len, + int is_final) { + enum XML_Status status = XML_Parse(parser, input, input_len, is_final); + while (status == XML_STATUS_SUSPENDED) { + status = XML_ResumeParser(parser); + } + return status; +} + +// When the fuzzer is compiled with instrumentation such as ASan, then the +// accesses in TouchString will fault if they access invalid memory (ie. detect +// either a use-after-free or buffer-overflow). By calling TouchString in each +// of the callbacks, we can check that the arguments meet the API specifications +// in terms of length/null-termination. no_optimize is used to ensure that the +// compiler has to emit actual memory reads, instead of removing them. +static volatile size_t no_optimize = 0; +static void TouchString(const XML_Char* ptr, int len=-1) { + if (!ptr) { + return; + } + + if (len == -1) { + for (XML_Char value = *ptr++; value; value = *ptr++) { + no_optimize += value; + } + } else { + for (int i = 0; i < len; ++i) { + no_optimize += ptr[i]; + } + } +} + +static void TouchChildNodes(XML_Content* content, bool topLevel=true) { + switch (content->type) { + case XML_CTYPE_EMPTY: + case XML_CTYPE_ANY: + assert(content->quant == XML_CQUANT_NONE); + assert(content->name == NULL); + assert(content->numchildren == 0); + assert(content->children == NULL); + break; + + case XML_CTYPE_MIXED: + assert(content->quant == XML_CQUANT_NONE + || content->quant == XML_CQUANT_REP); + assert(content->name == NULL); + for (int i = 0; i < content->numchildren; ++i) { + assert(content->children[i].type == XML_CTYPE_NAME); + assert(content->children[i].numchildren == 0); + TouchString(content->children[i].name); + } + break; + + case XML_CTYPE_NAME: + assert(content->numchildren == 0); + TouchString(content->name); + break; + + case XML_CTYPE_CHOICE: + case XML_CTYPE_SEQ: + assert(content->name == NULL); + for (int i = 0; i < content->numchildren; ++i) { + TouchChildNodes(&content->children[i], false); + } + break; + + default: + assert(false); + } +} + +static void XMLCALL +ElementDeclHandler(void* userData, const XML_Char* name, XML_Content* model) { + TouchString(name); + TouchChildNodes(model); + XML_FreeContentModel((XML_Parser)userData, model); +} + +static void XMLCALL +AttlistDeclHandler(void* userData, const XML_Char* elname, + const XML_Char* attname, const XML_Char* atttype, + const XML_Char* dflt, int isrequired) { + TouchString(elname); + TouchString(attname); + TouchString(atttype); + TouchString(dflt); +} + +static void XMLCALL +XmlDeclHandler(void* userData, const XML_Char* version, + const XML_Char* encoding, int standalone) { + TouchString(version); + TouchString(encoding); +} + +static void XMLCALL +StartElementHandler(void *userData, const XML_Char *name, + const XML_Char **atts) { + TouchString(name); + for (size_t i = 0; atts[i] != NULL; ++i) { + TouchString(atts[i]); + } +} + +static void XMLCALL +EndElementHandler(void *userData, const XML_Char *name) { + TouchString(name); +} + +static void XMLCALL +CharacterDataHandler(void* userData, const XML_Char* s, int len) { + TouchString(s, len); +} + +static void XMLCALL +ProcessingInstructionHandler(void* userData, const XML_Char* target, + const XML_Char* data) { + TouchString(target); + TouchString(data); +} + +static void XMLCALL +CommentHandler(void* userData, const XML_Char* data) { + TouchString(data); + // Use the comment handler to trigger parser suspend, so that we can get + // coverage of that code. + XML_StopParser((XML_Parser)userData, XML_TRUE); +} + +static void XMLCALL +StartCdataSectionHandler(void* userData) { +} + +static void XMLCALL +EndCdataSectionHandler(void* userData) { +} + +static void XMLCALL +DefaultHandler(void* userData, const XML_Char* s, int len) { + TouchString(s, len); +} + +static void XMLCALL +StartDoctypeDeclHandler(void* userData, const XML_Char* doctypeName, + const XML_Char* sysid, const XML_Char* pubid, + int has_internal_subset) { + TouchString(doctypeName); + TouchString(sysid); + TouchString(pubid); +} + +static void XMLCALL +EndDoctypeDeclHandler(void* userData) { +} + +static void XMLCALL +EntityDeclHandler(void *userData, const XML_Char *entityName, + int is_parameter_entity, const XML_Char *value, + int value_length, const XML_Char *base, + const XML_Char *systemId, const XML_Char *publicId, + const XML_Char *notationName) { + TouchString(entityName); + TouchString(value, value_length); + TouchString(base); + TouchString(systemId); + TouchString(publicId); + TouchString(notationName); +} + +static void XMLCALL +UnparsedEntityDeclHandler(void *userData, const XML_Char *entityName, + const XML_Char *base, const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName) { + TouchString(entityName); + TouchString(base); + TouchString(systemId); + TouchString(publicId); + TouchString(notationName); +} + +static void XMLCALL +NotationDeclHandler(void *userData, const XML_Char *notationName, + const XML_Char *base, const XML_Char *systemId, + const XML_Char *publicId) { + TouchString(notationName); + TouchString(base); + TouchString(systemId); + TouchString(publicId); +} + +static void XMLCALL +StartNamespaceDeclHandler(void *userData, const XML_Char *prefix, + const XML_Char *uri) { + TouchString(prefix); + TouchString(uri); +} + +static void XMLCALL +EndNamespaceDeclHandler(void *userData, const XML_Char *prefix) { + TouchString(prefix); +} + +static int XMLCALL +NotStandaloneHandler(void *userData) { + return XML_STATUS_OK; +} + +static int XMLCALL +ExternalEntityRefHandler(XML_Parser parser, const XML_Char *context, + const XML_Char *base, const XML_Char *systemId, + const XML_Char *publicId) { + int rc = XML_STATUS_ERROR; + TouchString(context); + TouchString(base); + TouchString(systemId); + TouchString(publicId); + + if (external_entity) { + XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, context, + encoding); + rc = Parse(ext_parser, (const XML_Char*)external_entity, + external_entity_size, 1); + XML_ParserFree(ext_parser); + } + + return rc; +} + +static void XMLCALL +SkippedEntityHandler(void *userData, const XML_Char *entityName, + int is_parameter_entity) { + TouchString(entityName); +} + +static int XMLCALL +UnknownEncodingHandler(void *encodingHandlerData, const XML_Char *name, + XML_Encoding *info) { + TouchString(name); + return XML_STATUS_ERROR; +} + +void InitializeParser(XML_Parser parser) { + XML_SetUserData(parser, (void*)parser); + XML_SetHashSalt(parser, 0x41414141); + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + + XML_SetElementDeclHandler(parser, ElementDeclHandler); + XML_SetAttlistDeclHandler(parser, AttlistDeclHandler); + XML_SetXmlDeclHandler(parser, XmlDeclHandler); + XML_SetElementHandler(parser, StartElementHandler, EndElementHandler); + XML_SetCharacterDataHandler(parser, CharacterDataHandler); + XML_SetProcessingInstructionHandler(parser, ProcessingInstructionHandler); + XML_SetCommentHandler(parser, CommentHandler); + XML_SetCdataSectionHandler(parser, StartCdataSectionHandler, + EndCdataSectionHandler); + // XML_SetDefaultHandler disables entity expansion + XML_SetDefaultHandlerExpand(parser, DefaultHandler); + XML_SetDoctypeDeclHandler(parser, StartDoctypeDeclHandler, + EndDoctypeDeclHandler); + XML_SetEntityDeclHandler(parser, EntityDeclHandler); + // NB: This is mutually exclusive with entity_decl_handler, and there isn't + // any significant code change between the two. + // XML_SetUnparsedEntityDeclHandler(p, UnparsedEntityDeclHandler); + XML_SetNotationDeclHandler(parser, NotationDeclHandler); + XML_SetNamespaceDeclHandler(parser, StartNamespaceDeclHandler, + EndNamespaceDeclHandler); + XML_SetNotStandaloneHandler(parser, NotStandaloneHandler); + XML_SetExternalEntityRefHandler(parser, ExternalEntityRefHandler); + XML_SetSkippedEntityHandler(parser, SkippedEntityHandler); + XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, (void*)parser); +} + +DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { + external_entity = nullptr; + + if (!testcase.actions_size()) { + return; + } + + SetEncoding(testcase.encoding()); + XML_Parser parser = XML_ParserCreateNS(encoding, '|'); + InitializeParser(parser); + + for (size_t i = 0; i < testcase.actions_size(); ++i) { + const auto& action = testcase.actions(i); + switch (action.action_case()) { + case xml_lpm_fuzzer::Action::kChunk: + if (XML_STATUS_ERROR == Parse(parser, + (const XML_Char*)action.chunk().data(), + action.chunk().size(), 0)) { + // Force a reset after parse error. + XML_ParserReset(parser, encoding); + } + break; + + case xml_lpm_fuzzer::Action::kLastChunk: + Parse(parser, (const XML_Char*)action.last_chunk().data(), + action.last_chunk().size(), 1); + XML_ParserReset(parser, encoding); + InitializeParser(parser); + break; + + case xml_lpm_fuzzer::Action::kReset: + XML_ParserReset(parser, encoding); + InitializeParser(parser); + break; + + case xml_lpm_fuzzer::Action::kExternalEntity: + external_entity = action.external_entity().data(); + external_entity_size = action.external_entity().size(); + break; + + default: + break; + } + } + + XML_ParserFree(parser); +} \ No newline at end of file diff --git a/expat/fuzz/xml_lpm_fuzzer.proto b/expat/fuzz/xml_lpm_fuzzer.proto new file mode 100644 index 00000000..53f52b53 --- /dev/null +++ b/expat/fuzz/xml_lpm_fuzzer.proto @@ -0,0 +1,56 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 2022 Google LLC + Licensed under the MIT license: + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +syntax = "proto2"; +package xml_lpm_fuzzer; + +enum Encoding { + UTF8 = 0; + UTF16 = 1; + ISO88591 = 2; + ASCII = 3; + UNKNOWN = 4; + NONE = 5; +} + +message Action { + oneof action { + string chunk = 1; + string last_chunk = 2; + bool reset = 3; + string external_entity = 4; + } +} + +message Testcase { + required Encoding encoding = 1; + repeated Action actions = 2; +} \ No newline at end of file From 02a6f9b25a39284aa6f0407f836c8a6e39751687 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Thu, 21 Jul 2022 16:44:21 +0200 Subject: [PATCH 02/36] fuzzers: Add support for failing allocations. --- expat/fuzz/xml_lpm_fuzzer.cpp | 41 +++++++++++++++++++++++++++++++-- expat/fuzz/xml_lpm_fuzzer.proto | 1 + 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 9dde59f3..ea8c8bee 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -30,8 +30,8 @@ */ #include -#include #include +#include #include "expat.h" #include "xml_lpm_fuzzer.pb.h" @@ -69,6 +69,37 @@ void SetEncoding(const xml_lpm_fuzzer::Encoding& e) { } } +static int allocation_count = 0; +static std::vector fail_allocations = {}; + +void* MallocHook(size_t size) { + for (auto index : fail_allocations) { + if (index == allocation_count) { + return NULL; + } + } + allocation_count += 1; + return malloc(size); +} + +void* ReallocHook(void* ptr, size_t size) { + for (auto index : fail_allocations) { + if (index == allocation_count) { + return NULL; + } + } + allocation_count += 1; + return realloc(ptr, size); +} + +void FreeHook(void* ptr) { + free(ptr); +} + +XML_Memory_Handling_Suite memory_handling_suite = { + MallocHook, ReallocHook, FreeHook +}; + void InitializeParser(XML_Parser parser); // We want a parse function that supports resumption, so that we can cover the @@ -353,8 +384,14 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { return; } + allocation_count = 0; + fail_allocations.clear(); + for (size_t i = 0; i < testcase.fail_allocations_size(); ++i) { + fail_allocations.push_back(testcase.fail_allocations(i)); + } + SetEncoding(testcase.encoding()); - XML_Parser parser = XML_ParserCreateNS(encoding, '|'); + XML_Parser parser = XML_ParserCreate_MM(encoding, &memory_handling_suite, "|"); InitializeParser(parser); for (size_t i = 0; i < testcase.actions_size(); ++i) { diff --git a/expat/fuzz/xml_lpm_fuzzer.proto b/expat/fuzz/xml_lpm_fuzzer.proto index 53f52b53..70993101 100644 --- a/expat/fuzz/xml_lpm_fuzzer.proto +++ b/expat/fuzz/xml_lpm_fuzzer.proto @@ -53,4 +53,5 @@ message Action { message Testcase { required Encoding encoding = 1; repeated Action actions = 2; + repeated int32 fail_allocations = 3; } \ No newline at end of file From 228447bbb12b8da8e8afdf089274624daf62d409 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Tue, 2 Aug 2022 14:36:21 +0200 Subject: [PATCH 03/36] fuzzers: Pin tagged versions of protobuf and libprotobuf-mutator This change modifies the build to pull in and compile libprotobuf as well as libprotobuf-mutator to avoid needing a preinstalled copy of protobuf/protoc. --- expat/CMakeLists.txt | 73 ++++++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index 09264a3e..fe2f86bb 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -670,28 +670,53 @@ if(EXPAT_BUILD_FUZZERS) endforeach() endforeach() - find_package(Protobuf REQUIRED) + # Only include protobuf and libprotobuf-mutator here so that we don't build + # them in non-fuzz configurations. + include(FetchContent) - # Only include libprotobuf-mutator here so we don't build it in non-fuzz - # configurations. - include(ExternalProject) - - set(ProtobufMutator_PREFIX libprotobuf-mutator) - set(ProtobufMutator_PATH ${CMAKE_CURRENT_BINARY_DIR}/${ProtobufMutator_PREFIX}/src/${ProtobufMutator_PREFIX}) - set(ProtobufMutator_BUILD_PATH ${ProtobufMutator_PATH}-build) - set(ProtobufMutator_INCLUDE_DIR ${ProtobufMutator_PATH}) - set(ProtobufMutator_LIBRARIES ${ProtobufMutator_BUILD_PATH}/src/libfuzzer/libprotobuf-mutator-libfuzzer.a ${ProtobufMutator_BUILD_PATH}/src/libprotobuf-mutator.a) - - ExternalProject_Add( - ${ProtobufMutator_PREFIX} - PREFIX ${ProtobufMutator_PREFIX} - GIT_REPOSITORY https://github.com/google/libprotobuf-mutator.git - GIT_TAG master + FetchContent_Declare( + Protobuf + GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git + GIT_TAG v3.20.1 CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} - BUILD_BYPRODUCTS ${ProtobufMutator_LIBRARIES} - UPDATE_COMMAND true - INSTALL_COMMAND true) + SOURCE_SUBDIR cmake + OVERRIDE_FIND_PACKAGE) + set(protobuf_BUILD_TESTS OFF CACHE BOOL "No protobuf tests") + FetchContent_MakeAvailable(Protobuf) + FetchContent_GetProperties( + Protobuf + SOURCE_DIR Protobuf_SOURCE_DIR + BINARY_DIR Protobuf_BINARY_DIR) + + FetchContent_Declare( + ProtobufMutator + GIT_REPOSITORY https://github.com/google/libprotobuf-mutator.git + GIT_TAG v1.0 + CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}) + + # This is enough for libprotobuf-mutator build to find our build of protobuf + set(Protobuf_INCLUDE_DIR ${Protobuf_SOURCE_DIR}/src) + set(Protobuf_LIBRARIES ${Protobuf_BINARY_DIR}/libprotobuf.a) + set(Protobuf_PROTOC_EXECUTABLE ${Protobuf_BINARY_DIR}/protoc) + + # This combination of flags is necessary to prevent libprotobuf-mutator from + # trying to build another copy of expat internally. + set(LIB_PROTO_MUTATOR_TESTING OFF CACHE BOOL "No libprotobuf-mutator tests") + set(LIB_PROTO_MUTATOR_FUZZER_LIBRARIES "") + set(LIB_PROTO_MUTATOR_HAS_SANITIZE_FUZZER "") + + FetchContent_MakeAvailable(ProtobufMutator) + FetchContent_GetProperties( + ProtobufMutator + SOURCE_DIR ProtobufMutator_SOURCE_DIR + BINARY_DIR ProtobufMutator_BINARY_DIR) + + set(ProtobufMutator_INCLUDE_DIR ${ProtobufMutator_SOURCE_DIR}) + + # We need to include this to get the `protobuf_generate_cpp` rule. + include(FindProtobuf) protobuf_generate_cpp(XML_LPM_FUZZER_PROTO_SRCS XML_LPM_FUZZER_PROTO_HDRS @@ -700,12 +725,14 @@ if(EXPAT_BUILD_FUZZERS) add_executable(xml_lpm_fuzzer fuzz/xml_lpm_fuzzer.cpp ${XML_LPM_FUZZER_PROTO_SRCS}) + set_target_properties(xml_lpm_fuzzer PROPERTIES LINKER_LANGUAGE CXX) - target_include_directories(xml_lpm_fuzzer PUBLIC ${ProtobufMutator_INCLUDE_DIR}) + target_include_directories(xml_lpm_fuzzer PUBLIC + ${Protobuf_INCLUDE_DIR} + ${ProtobufMutator_INCLUDE_DIR}) target_link_libraries(xml_lpm_fuzzer - fuzzpat - ${Protobuf_LIBRARIES} - ${ProtobufMutator_LIBRARIES}) + fuzzpat libprotobuf protobuf-mutator-libfuzzer) + # NOTE: Avoiding target_link_options here only because it needs CMake >=3.13 if(EXPAT_OSSFUZZ_BUILD) set_target_properties(xml_lpm_fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) From b1d40decd9790a0f6f497e3f6f61f35e2aa263ce Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sat, 1 Feb 2025 19:53:35 +0100 Subject: [PATCH 04/36] Revert "fuzzers: Pin tagged versions of protobuf and libprotobuf-mutator" This reverts commit 99314b5d946c0b6851c97714a9b4965284843717. --- expat/CMakeLists.txt | 73 ++++++++++++++------------------------------ 1 file changed, 23 insertions(+), 50 deletions(-) diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index fdf3497f..c10cefa9 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -756,53 +756,28 @@ if(EXPAT_BUILD_FUZZERS) endforeach() endforeach() - # Only include protobuf and libprotobuf-mutator here so that we don't build - # them in non-fuzz configurations. - include(FetchContent) + find_package(Protobuf REQUIRED) - FetchContent_Declare( - Protobuf - GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git - GIT_TAG v3.20.1 + # Only include libprotobuf-mutator here so we don't build it in non-fuzz + # configurations. + include(ExternalProject) + + set(ProtobufMutator_PREFIX libprotobuf-mutator) + set(ProtobufMutator_PATH ${CMAKE_CURRENT_BINARY_DIR}/${ProtobufMutator_PREFIX}/src/${ProtobufMutator_PREFIX}) + set(ProtobufMutator_BUILD_PATH ${ProtobufMutator_PATH}-build) + set(ProtobufMutator_INCLUDE_DIR ${ProtobufMutator_PATH}) + set(ProtobufMutator_LIBRARIES ${ProtobufMutator_BUILD_PATH}/src/libfuzzer/libprotobuf-mutator-libfuzzer.a ${ProtobufMutator_BUILD_PATH}/src/libprotobuf-mutator.a) + + ExternalProject_Add( + ${ProtobufMutator_PREFIX} + PREFIX ${ProtobufMutator_PREFIX} + GIT_REPOSITORY https://github.com/google/libprotobuf-mutator.git + GIT_TAG master CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} - SOURCE_SUBDIR cmake - OVERRIDE_FIND_PACKAGE) - set(protobuf_BUILD_TESTS OFF CACHE BOOL "No protobuf tests") - FetchContent_MakeAvailable(Protobuf) - FetchContent_GetProperties( - Protobuf - SOURCE_DIR Protobuf_SOURCE_DIR - BINARY_DIR Protobuf_BINARY_DIR) - - FetchContent_Declare( - ProtobufMutator - GIT_REPOSITORY https://github.com/google/libprotobuf-mutator.git - GIT_TAG v1.0 - CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}) - - # This is enough for libprotobuf-mutator build to find our build of protobuf - set(Protobuf_INCLUDE_DIR ${Protobuf_SOURCE_DIR}/src) - set(Protobuf_LIBRARIES ${Protobuf_BINARY_DIR}/libprotobuf.a) - set(Protobuf_PROTOC_EXECUTABLE ${Protobuf_BINARY_DIR}/protoc) - - # This combination of flags is necessary to prevent libprotobuf-mutator from - # trying to build another copy of expat internally. - set(LIB_PROTO_MUTATOR_TESTING OFF CACHE BOOL "No libprotobuf-mutator tests") - set(LIB_PROTO_MUTATOR_FUZZER_LIBRARIES "") - set(LIB_PROTO_MUTATOR_HAS_SANITIZE_FUZZER "") - - FetchContent_MakeAvailable(ProtobufMutator) - FetchContent_GetProperties( - ProtobufMutator - SOURCE_DIR ProtobufMutator_SOURCE_DIR - BINARY_DIR ProtobufMutator_BINARY_DIR) - - set(ProtobufMutator_INCLUDE_DIR ${ProtobufMutator_SOURCE_DIR}) - - # We need to include this to get the `protobuf_generate_cpp` rule. - include(FindProtobuf) + BUILD_BYPRODUCTS ${ProtobufMutator_LIBRARIES} + UPDATE_COMMAND true + INSTALL_COMMAND true) protobuf_generate_cpp(XML_LPM_FUZZER_PROTO_SRCS XML_LPM_FUZZER_PROTO_HDRS @@ -811,14 +786,12 @@ if(EXPAT_BUILD_FUZZERS) add_executable(xml_lpm_fuzzer fuzz/xml_lpm_fuzzer.cpp ${XML_LPM_FUZZER_PROTO_SRCS}) - set_target_properties(xml_lpm_fuzzer PROPERTIES LINKER_LANGUAGE CXX) - target_include_directories(xml_lpm_fuzzer PUBLIC - ${Protobuf_INCLUDE_DIR} - ${ProtobufMutator_INCLUDE_DIR}) + target_include_directories(xml_lpm_fuzzer PUBLIC ${ProtobufMutator_INCLUDE_DIR}) target_link_libraries(xml_lpm_fuzzer - fuzzpat libprotobuf protobuf-mutator-libfuzzer) - + fuzzpat + ${Protobuf_LIBRARIES} + ${ProtobufMutator_LIBRARIES}) # NOTE: Avoiding target_link_options here only because it needs CMake >=3.13 if(EXPAT_OSSFUZZ_BUILD) set_target_properties(xml_lpm_fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) From c87f28da40fc2316799077f08b08e66244622ac0 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 20:45:23 +0100 Subject: [PATCH 05/36] fuzzers|cmake: Enable C++ for EXPAT_BUILD_FUZZERS --- expat/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index c10cefa9..6a77ef63 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -169,7 +169,7 @@ if(NOT _EXPAT_HELP) mark_as_advanced(_EXPAT_M32) endif() -if(EXPAT_BUILD_TESTS) +if(EXPAT_BUILD_TESTS OR EXPAT_BUILD_FUZZERS) # We have to call enable_language() before modifying any CMAKE_CXX_* variables enable_language(CXX) From d9a91c655d4dfd4e96940ffcad0d4f93eccb9eed Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sat, 1 Feb 2025 23:06:36 +0100 Subject: [PATCH 06/36] fuzzers|cmake: Compile as C++17 for recent Abseil --- expat/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index 6a77ef63..b9a2a1e4 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -173,7 +173,11 @@ if(EXPAT_BUILD_TESTS OR EXPAT_BUILD_FUZZERS) # We have to call enable_language() before modifying any CMAKE_CXX_* variables enable_language(CXX) - set(CMAKE_CXX_STANDARD 11) + if (EXPAT_BUILD_FUZZERS) + set(CMAKE_CXX_STANDARD 17) # for std::string_view for Abseil for libprotobuf-mutator + else() + set(CMAKE_CXX_STANDARD 11) + endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # i.e. -std=c++11 rather than default -std=gnu++11 endif() From eedfa51d994735289d815786a29f77d7921e6c75 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sat, 1 Feb 2025 19:54:59 +0100 Subject: [PATCH 07/36] fuzzers|cmake: Downgrade and pin libprotobuf-mutator to v1.1-7-g50ef915 On Ubuntu 24.04 the symptom with more recent 1.3 was: > [ 37%] Building CXX object src/CMakeFiles/protobuf-mutator.dir/text_format.cc.o > cd /home/runner/work/libexpat-private/libexpat-private/expat/build/libprotobuf-mutator/src/libprotobuf-mutator-build/src && /usr/lib/llvm-19/bin/clang++ -I/home/runner/work/libexpat-private/libexpat-private/expat/build/libprotobuf-mutator/src/libprotobuf-mutator -I/home/runner/work/libexpat-private/libexpat-private/expat/build/libprotobuf-mutator/src/libprotobuf-mutator-build -fno-exceptions -Wno-deprecated-declarations -Wall -Wstring-conversion -std=c++17 -fsanitize-coverage=0 -MD -MT src/CMakeFiles/protobuf-mutator.dir/text_format.cc.o -MF CMakeFiles/protobuf-mutator.dir/text_format.cc.o.d -o CMakeFiles/protobuf-mutator.dir/text_format.cc.o -c /home/runner/work/libexpat-private/libexpat-private/expat/build/libprotobuf-mutator/src/libprotobuf-mutator/src/text_format.cc > In file included from /home/runner/work/libexpat-private/libexpat-private/expat/build/libprotobuf-mutator/src/libprotobuf-mutator/src/mutator.cc:27: > /home/runner/work/libexpat-private/libexpat-private/expat/build/libprotobuf-mutator/src/libprotobuf-mutator/src/field_instance.h:193:50: error: no member named 'requires_utf8_validation' in 'google::protobuf::FieldDescriptor' > 193 | bool EnforceUtf8() const { return descriptor_->requires_utf8_validation(); } > | ~~~~~~~~~~~ ^ --- expat/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index b9a2a1e4..0575f811 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -776,7 +776,7 @@ if(EXPAT_BUILD_FUZZERS) ${ProtobufMutator_PREFIX} PREFIX ${ProtobufMutator_PREFIX} GIT_REPOSITORY https://github.com/google/libprotobuf-mutator.git - GIT_TAG master + GIT_TAG 50ef9159bb838931d83e5bbd77eeec05fc50f57d # v1.1-7-g50ef915, last before commit "Switch to requires_utf8_validation" CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} BUILD_BYPRODUCTS ${ProtobufMutator_LIBRARIES} From c2fd39564c05aab3c46eca434c93406c041ea3e7 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sat, 1 Feb 2025 23:07:03 +0100 Subject: [PATCH 08/36] fuzzers|cmake: Patch default -Werror out of libprotobuf-mutator .. and make it use C++ 17 for recent Abseil --- expat/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index 0575f811..79287b5d 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -780,6 +780,7 @@ if(EXPAT_BUILD_FUZZERS) CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} BUILD_BYPRODUCTS ${ProtobufMutator_LIBRARIES} + PATCH_COMMAND sed -e "s,-Werror, ," -e "s,CMAKE_CXX_STANDARD [0-9]\\+,CMAKE_CXX_STANDARD 17," -i.bak ${ProtobufMutator_PATH}/CMakeLists.txt UPDATE_COMMAND true INSTALL_COMMAND true) From 2fd3844a7c98cc476a14df31582834156d34c240 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sat, 1 Feb 2025 22:41:51 +0100 Subject: [PATCH 09/36] fuzzers|cmake: Stop compiling libprotobuf-mutator with tests --- expat/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index 79287b5d..e298d3eb 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -778,7 +778,7 @@ if(EXPAT_BUILD_FUZZERS) GIT_REPOSITORY https://github.com/google/libprotobuf-mutator.git GIT_TAG 50ef9159bb838931d83e5bbd77eeec05fc50f57d # v1.1-7-g50ef915, last before commit "Switch to requires_utf8_validation" CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} + CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} -DLIB_PROTO_MUTATOR_TESTING:BOOL=OFF BUILD_BYPRODUCTS ${ProtobufMutator_LIBRARIES} PATCH_COMMAND sed -e "s,-Werror, ," -e "s,CMAKE_CXX_STANDARD [0-9]\\+,CMAKE_CXX_STANDARD 17," -i.bak ${ProtobufMutator_PATH}/CMakeLists.txt UPDATE_COMMAND true From d7e41e2de81768122df9fab9fe8c57bf91652f77 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 19:04:48 +0100 Subject: [PATCH 10/36] fuzzers|cmake: Link xml_lpm_fuzzer against Abseil, explicitly --- expat/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index e298d3eb..47179e29 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -760,6 +760,7 @@ if(EXPAT_BUILD_FUZZERS) endforeach() endforeach() + find_package(absl REQUIRED) find_package(Protobuf REQUIRED) # Only include libprotobuf-mutator here so we don't build it in non-fuzz @@ -795,6 +796,7 @@ if(EXPAT_BUILD_FUZZERS) target_include_directories(xml_lpm_fuzzer PUBLIC ${ProtobufMutator_INCLUDE_DIR}) target_link_libraries(xml_lpm_fuzzer fuzzpat + ${absl_LIBRARIES} ${Protobuf_LIBRARIES} ${ProtobufMutator_LIBRARIES}) # NOTE: Avoiding target_link_options here only because it needs CMake >=3.13 From ba8744ae19c066f06b622c003c170ae715cc161b Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 19:28:41 +0100 Subject: [PATCH 11/36] fuzzers|cmake: Fix parallel build for xml_lpm_fuzzer --- expat/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index 47179e29..2a6bd94e 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -799,6 +799,8 @@ if(EXPAT_BUILD_FUZZERS) ${absl_LIBRARIES} ${Protobuf_LIBRARIES} ${ProtobufMutator_LIBRARIES}) + add_dependencies(xml_lpm_fuzzer ${ProtobufMutator_PREFIX}) + # NOTE: Avoiding target_link_options here only because it needs CMake >=3.13 if(EXPAT_OSSFUZZ_BUILD) set_target_properties(xml_lpm_fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) From 5551e205d25e2bfe7ab2586f1511f783820512fb Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 20:20:06 +0100 Subject: [PATCH 12/36] fuzzers|cmake: Drop redundant linker language to simplify The other fuzzers need it for EXPAT_OSSFUZZ_BUILD when C becomes C++ but not this one. --- expat/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index 2a6bd94e..cd02fa48 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -792,7 +792,6 @@ if(EXPAT_BUILD_FUZZERS) add_executable(xml_lpm_fuzzer fuzz/xml_lpm_fuzzer.cpp ${XML_LPM_FUZZER_PROTO_SRCS}) - set_target_properties(xml_lpm_fuzzer PROPERTIES LINKER_LANGUAGE CXX) target_include_directories(xml_lpm_fuzzer PUBLIC ${ProtobufMutator_INCLUDE_DIR}) target_link_libraries(xml_lpm_fuzzer fuzzpat @@ -804,7 +803,6 @@ if(EXPAT_BUILD_FUZZERS) # NOTE: Avoiding target_link_options here only because it needs CMake >=3.13 if(EXPAT_OSSFUZZ_BUILD) set_target_properties(xml_lpm_fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) - set_target_properties(xml_lpm_fuzzer PROPERTIES LINKER_LANGUAGE "CXX") else() target_compile_options(xml_lpm_fuzzer PRIVATE -fsanitize=fuzzer-no-link) set_target_properties(xml_lpm_fuzzer PROPERTIES LINK_FLAGS -fsanitize=fuzzer) From 2ca8b39167feadaf497d742524cad719fb7b2b9d Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 00:39:58 +0100 Subject: [PATCH 13/36] xml_lpm_fuzzer: Protect assert(...) from NDEBUG --- expat/fuzz/xml_lpm_fuzzer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index ea8c8bee..52c99d96 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -29,6 +29,10 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#if defined(NDEBUG) +# undef NDEBUG // because checks below rely on assert(...) +#endif + #include #include #include From 2b73e1bc00d0c398035f5d4e6c8812b2386b70c4 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 00:42:03 +0100 Subject: [PATCH 14/36] xml_lpm_fuzzer: Mark variable "encoding" as global This resolves variable shadowing in a few places also, e.g. in XmlDeclHandler and UnknownEncodingHandler. --- expat/fuzz/xml_lpm_fuzzer.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 52c99d96..ec4f39d9 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -41,34 +41,34 @@ #include "xml_lpm_fuzzer.pb.h" #include "src/libfuzzer/libfuzzer_macro.h" -static const char* encoding = nullptr; +static const char* g_encoding = nullptr; static const char* external_entity = nullptr; static size_t external_entity_size = 0; void SetEncoding(const xml_lpm_fuzzer::Encoding& e) { switch (e) { case xml_lpm_fuzzer::Encoding::UTF8: - encoding = "UTF-8"; + g_encoding = "UTF-8"; break; case xml_lpm_fuzzer::Encoding::UTF16: - encoding = "UTF-16"; + g_encoding = "UTF-16"; break; case xml_lpm_fuzzer::Encoding::ISO88591: - encoding = "ISO-8859-1"; + g_encoding = "ISO-8859-1"; break; case xml_lpm_fuzzer::Encoding::ASCII: - encoding = "US-ASCII"; + g_encoding = "US-ASCII"; break; case xml_lpm_fuzzer::Encoding::NONE: - encoding = NULL; + g_encoding = NULL; break; default: - encoding = "UNKNOWN"; + g_encoding = "UNKNOWN"; break; } } @@ -328,7 +328,7 @@ ExternalEntityRefHandler(XML_Parser parser, const XML_Char *context, if (external_entity) { XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, context, - encoding); + g_encoding); rc = Parse(ext_parser, (const XML_Char*)external_entity, external_entity_size, 1); XML_ParserFree(ext_parser); @@ -395,7 +395,7 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { } SetEncoding(testcase.encoding()); - XML_Parser parser = XML_ParserCreate_MM(encoding, &memory_handling_suite, "|"); + XML_Parser parser = XML_ParserCreate_MM(g_encoding, &memory_handling_suite, "|"); InitializeParser(parser); for (size_t i = 0; i < testcase.actions_size(); ++i) { @@ -406,19 +406,19 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { (const XML_Char*)action.chunk().data(), action.chunk().size(), 0)) { // Force a reset after parse error. - XML_ParserReset(parser, encoding); + XML_ParserReset(parser, g_encoding); } break; case xml_lpm_fuzzer::Action::kLastChunk: Parse(parser, (const XML_Char*)action.last_chunk().data(), action.last_chunk().size(), 1); - XML_ParserReset(parser, encoding); + XML_ParserReset(parser, g_encoding); InitializeParser(parser); break; case xml_lpm_fuzzer::Action::kReset: - XML_ParserReset(parser, encoding); + XML_ParserReset(parser, g_encoding); InitializeParser(parser); break; From 59771b8f7f6c4126e26b17249e4e5f5127c171f5 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 00:46:23 +0100 Subject: [PATCH 15/36] xml_lpm_fuzzer: Mark variables external_entity{,_size} as global --- expat/fuzz/xml_lpm_fuzzer.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index ec4f39d9..8f371cb1 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -42,8 +42,8 @@ #include "src/libfuzzer/libfuzzer_macro.h" static const char* g_encoding = nullptr; -static const char* external_entity = nullptr; -static size_t external_entity_size = 0; +static const char* g_external_entity = nullptr; +static size_t g_external_entity_size = 0; void SetEncoding(const xml_lpm_fuzzer::Encoding& e) { switch (e) { @@ -326,11 +326,11 @@ ExternalEntityRefHandler(XML_Parser parser, const XML_Char *context, TouchString(systemId); TouchString(publicId); - if (external_entity) { + if (g_external_entity) { XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, context, g_encoding); - rc = Parse(ext_parser, (const XML_Char*)external_entity, - external_entity_size, 1); + rc = Parse(ext_parser, (const XML_Char*)g_external_entity, + g_external_entity_size, 1); XML_ParserFree(ext_parser); } @@ -382,7 +382,7 @@ void InitializeParser(XML_Parser parser) { } DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { - external_entity = nullptr; + g_external_entity = nullptr; if (!testcase.actions_size()) { return; @@ -423,8 +423,8 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { break; case xml_lpm_fuzzer::Action::kExternalEntity: - external_entity = action.external_entity().data(); - external_entity_size = action.external_entity().size(); + g_external_entity = action.external_entity().data(); + g_external_entity_size = action.external_entity().size(); break; default: From 2bb8a2942812878cfcf7616598dd8079142bd29a Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 00:47:32 +0100 Subject: [PATCH 16/36] xml_lpm_fuzzer: Mark variable "allocation_count" as global --- expat/fuzz/xml_lpm_fuzzer.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 8f371cb1..6c467e7d 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -73,26 +73,26 @@ void SetEncoding(const xml_lpm_fuzzer::Encoding& e) { } } -static int allocation_count = 0; +static int g_allocation_count = 0; static std::vector fail_allocations = {}; void* MallocHook(size_t size) { for (auto index : fail_allocations) { - if (index == allocation_count) { + if (index == g_allocation_count) { return NULL; } } - allocation_count += 1; + g_allocation_count += 1; return malloc(size); } void* ReallocHook(void* ptr, size_t size) { for (auto index : fail_allocations) { - if (index == allocation_count) { + if (index == g_allocation_count) { return NULL; } } - allocation_count += 1; + g_allocation_count += 1; return realloc(ptr, size); } @@ -388,7 +388,7 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { return; } - allocation_count = 0; + g_allocation_count = 0; fail_allocations.clear(); for (size_t i = 0; i < testcase.fail_allocations_size(); ++i) { fail_allocations.push_back(testcase.fail_allocations(i)); From da8219b9afc73048e0e12e7f1ca776569f67e731 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 00:50:00 +0100 Subject: [PATCH 17/36] xml_lpm_fuzzer: Mark variable "fail_allocations" as global --- expat/fuzz/xml_lpm_fuzzer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 6c467e7d..11de0567 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -74,10 +74,10 @@ void SetEncoding(const xml_lpm_fuzzer::Encoding& e) { } static int g_allocation_count = 0; -static std::vector fail_allocations = {}; +static std::vector g_fail_allocations = {}; void* MallocHook(size_t size) { - for (auto index : fail_allocations) { + for (auto index : g_fail_allocations) { if (index == g_allocation_count) { return NULL; } @@ -87,7 +87,7 @@ void* MallocHook(size_t size) { } void* ReallocHook(void* ptr, size_t size) { - for (auto index : fail_allocations) { + for (auto index : g_fail_allocations) { if (index == g_allocation_count) { return NULL; } @@ -389,9 +389,9 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { } g_allocation_count = 0; - fail_allocations.clear(); + g_fail_allocations.clear(); for (size_t i = 0; i < testcase.fail_allocations_size(); ++i) { - fail_allocations.push_back(testcase.fail_allocations(i)); + g_fail_allocations.push_back(testcase.fail_allocations(i)); } SetEncoding(testcase.encoding()); From 5f42436e02a531e0cfbb7a64377af19095b8db39 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 00:55:08 +0100 Subject: [PATCH 18/36] xml_lpm_fuzzer: Fix mistaken use of XML_Char --- expat/fuzz/xml_lpm_fuzzer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 11de0567..4e2a5658 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -108,7 +108,7 @@ void InitializeParser(XML_Parser parser); // We want a parse function that supports resumption, so that we can cover the // suspend/resume code. -enum XML_Status Parse(XML_Parser parser, const XML_Char* input, int input_len, +enum XML_Status Parse(XML_Parser parser, const char* input, int input_len, int is_final) { enum XML_Status status = XML_Parse(parser, input, input_len, is_final); while (status == XML_STATUS_SUSPENDED) { @@ -329,7 +329,7 @@ ExternalEntityRefHandler(XML_Parser parser, const XML_Char *context, if (g_external_entity) { XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, context, g_encoding); - rc = Parse(ext_parser, (const XML_Char*)g_external_entity, + rc = Parse(ext_parser, g_external_entity, g_external_entity_size, 1); XML_ParserFree(ext_parser); } @@ -403,7 +403,7 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { switch (action.action_case()) { case xml_lpm_fuzzer::Action::kChunk: if (XML_STATUS_ERROR == Parse(parser, - (const XML_Char*)action.chunk().data(), + action.chunk().data(), action.chunk().size(), 0)) { // Force a reset after parse error. XML_ParserReset(parser, g_encoding); @@ -411,7 +411,7 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { break; case xml_lpm_fuzzer::Action::kLastChunk: - Parse(parser, (const XML_Char*)action.last_chunk().data(), + Parse(parser, action.last_chunk().data(), action.last_chunk().size(), 1); XML_ParserReset(parser, g_encoding); InitializeParser(parser); From e183cb98117683b188094785d143438e8b503321 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 01:09:21 +0100 Subject: [PATCH 19/36] xml_lpm_fuzzer: Be more thorough in model validation --- expat/fuzz/xml_lpm_fuzzer.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 4e2a5658..10166f93 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -156,18 +156,29 @@ static void TouchChildNodes(XML_Content* content, bool topLevel=true) { assert(content->name == NULL); for (int i = 0; i < content->numchildren; ++i) { assert(content->children[i].type == XML_CTYPE_NAME); + assert(content->children[i].quant == XML_CQUANT_NONE); assert(content->children[i].numchildren == 0); + assert(content->children[i].children == NULL); TouchString(content->children[i].name); } break; case XML_CTYPE_NAME: + assert((content->quant == XML_CQUANT_NONE) + || (content->quant == XML_CQUANT_OPT) + || (content->quant == XML_CQUANT_REP) + || (content->quant == XML_CQUANT_PLUS)); assert(content->numchildren == 0); + assert(content->children == NULL); TouchString(content->name); break; case XML_CTYPE_CHOICE: case XML_CTYPE_SEQ: + assert((content->quant == XML_CQUANT_NONE) + || (content->quant == XML_CQUANT_OPT) + || (content->quant == XML_CQUANT_REP) + || (content->quant == XML_CQUANT_PLUS)); assert(content->name == NULL); for (int i = 0; i < content->numchildren; ++i) { TouchChildNodes(&content->children[i], false); From 4962f317d220bb8f0fc93f355171468e864f0b05 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 01:21:25 +0100 Subject: [PATCH 20/36] xml_lpm_fuzzer: Rename function to better match its nature --- expat/fuzz/xml_lpm_fuzzer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 10166f93..0e14c889 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -140,7 +140,7 @@ static void TouchString(const XML_Char* ptr, int len=-1) { } } -static void TouchChildNodes(XML_Content* content, bool topLevel=true) { +static void TouchNodeAndRecurse(XML_Content* content, bool topLevel=true) { switch (content->type) { case XML_CTYPE_EMPTY: case XML_CTYPE_ANY: @@ -181,7 +181,7 @@ static void TouchChildNodes(XML_Content* content, bool topLevel=true) { || (content->quant == XML_CQUANT_PLUS)); assert(content->name == NULL); for (int i = 0; i < content->numchildren; ++i) { - TouchChildNodes(&content->children[i], false); + TouchNodeAndRecurse(&content->children[i], false); } break; @@ -193,7 +193,7 @@ static void TouchChildNodes(XML_Content* content, bool topLevel=true) { static void XMLCALL ElementDeclHandler(void* userData, const XML_Char* name, XML_Content* model) { TouchString(name); - TouchChildNodes(model); + TouchNodeAndRecurse(model); XML_FreeContentModel((XML_Parser)userData, model); } From d7736d9cfa13a765029ebec401fb7f8efa5e76b0 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 01:22:05 +0100 Subject: [PATCH 21/36] xml_lpm_fuzzer: Resolve unused function parameter --- expat/fuzz/xml_lpm_fuzzer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 0e14c889..022108f8 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -140,7 +140,7 @@ static void TouchString(const XML_Char* ptr, int len=-1) { } } -static void TouchNodeAndRecurse(XML_Content* content, bool topLevel=true) { +static void TouchNodeAndRecurse(XML_Content* content) { switch (content->type) { case XML_CTYPE_EMPTY: case XML_CTYPE_ANY: @@ -181,7 +181,7 @@ static void TouchNodeAndRecurse(XML_Content* content, bool topLevel=true) { || (content->quant == XML_CQUANT_PLUS)); assert(content->name == NULL); for (int i = 0; i < content->numchildren; ++i) { - TouchNodeAndRecurse(&content->children[i], false); + TouchNodeAndRecurse(&content->children[i]); } break; From 6933ee68f1b7714f4559d3e30942afbbd4263ac9 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 01:27:32 +0100 Subject: [PATCH 22/36] xml_lpm_fuzzer: Resolve dead code --- expat/fuzz/xml_lpm_fuzzer.cpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 022108f8..0e42c1e7 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -288,18 +288,6 @@ EntityDeclHandler(void *userData, const XML_Char *entityName, TouchString(notationName); } -static void XMLCALL -UnparsedEntityDeclHandler(void *userData, const XML_Char *entityName, - const XML_Char *base, const XML_Char *systemId, - const XML_Char *publicId, - const XML_Char *notationName) { - TouchString(entityName); - TouchString(base); - TouchString(systemId); - TouchString(publicId); - TouchString(notationName); -} - static void XMLCALL NotationDeclHandler(void *userData, const XML_Char *notationName, const XML_Char *base, const XML_Char *systemId, @@ -379,10 +367,9 @@ void InitializeParser(XML_Parser parser) { XML_SetDefaultHandlerExpand(parser, DefaultHandler); XML_SetDoctypeDeclHandler(parser, StartDoctypeDeclHandler, EndDoctypeDeclHandler); + // Note: This is mutually exclusive with XML_SetUnparsedEntityDeclHandler, + // and there isn't any significant code change between the two. XML_SetEntityDeclHandler(parser, EntityDeclHandler); - // NB: This is mutually exclusive with entity_decl_handler, and there isn't - // any significant code change between the two. - // XML_SetUnparsedEntityDeclHandler(p, UnparsedEntityDeclHandler); XML_SetNotationDeclHandler(parser, NotationDeclHandler); XML_SetNamespaceDeclHandler(parser, StartNamespaceDeclHandler, EndNamespaceDeclHandler); From ea492aa54df8208783694cfa2df488de5fd71f4e Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 01:47:28 +0100 Subject: [PATCH 23/36] xml_lpm_fuzzer: Add missing call to InitializeParser after XML_ParserReset --- expat/fuzz/xml_lpm_fuzzer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 0e42c1e7..af5ed9b5 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -405,6 +405,7 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { action.chunk().size(), 0)) { // Force a reset after parse error. XML_ParserReset(parser, g_encoding); + InitializeParser(parser); } break; From ea98a8797124204c5fbfac8b9863b97b33eaf287 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 01:49:45 +0100 Subject: [PATCH 24/36] xml_lpm_fuzzer: Add trailing newline --- expat/fuzz/xml_lpm_fuzzer.cpp | 2 +- expat/fuzz/xml_lpm_fuzzer.proto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index af5ed9b5..bb108fbf 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -432,4 +432,4 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { } XML_ParserFree(parser); -} \ No newline at end of file +} diff --git a/expat/fuzz/xml_lpm_fuzzer.proto b/expat/fuzz/xml_lpm_fuzzer.proto index 70993101..3bd3a5b3 100644 --- a/expat/fuzz/xml_lpm_fuzzer.proto +++ b/expat/fuzz/xml_lpm_fuzzer.proto @@ -54,4 +54,4 @@ message Testcase { required Encoding encoding = 1; repeated Action actions = 2; repeated int32 fail_allocations = 3; -} \ No newline at end of file +} From 48afe247ce44355d6a0643f8a3f38ba9c74f3e31 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 02:00:38 +0100 Subject: [PATCH 25/36] xml_lpm_fuzzer|cmake: Replace -fsanitize=fuzzer-no-link by -fsanitize=fuzzer Same as commit bf9caf7ac4cd66fe1ca7f13cbef13629ffb20926, different target. --- expat/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index cd02fa48..7ae338e6 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -804,7 +804,7 @@ if(EXPAT_BUILD_FUZZERS) if(EXPAT_OSSFUZZ_BUILD) set_target_properties(xml_lpm_fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) else() - target_compile_options(xml_lpm_fuzzer PRIVATE -fsanitize=fuzzer-no-link) + target_compile_options(xml_lpm_fuzzer PRIVATE -fsanitize=fuzzer) set_target_properties(xml_lpm_fuzzer PROPERTIES LINK_FLAGS -fsanitize=fuzzer) endif() set_property(TARGET xml_lpm_fuzzer PROPERTY RUNTIME_OUTPUT_DIRECTORY fuzz) From 15b1af67169cf98405e907e29f07d814bb6a34a6 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 21:02:31 +0100 Subject: [PATCH 26/36] xml_lpm_fuzzer: Address warning -Wsign-compare Symptom was: > [..]/expat/fuzz/xml_lpm_fuzzer.cpp:157:25: error: comparison of integers of different signs: 'int' and 'unsigned int' [-Werror,-Wsign-compare] > 157 | for (int i = 0; i < content->numchildren; ++i) { > | ~ ^ ~~~~~~~~~~~~~~~~~~~~ > [..]/expat/fuzz/xml_lpm_fuzzer.cpp:183:25: error: comparison of integers of different signs: 'int' and 'unsigned int' [-Werror,-Wsign-compare] > 183 | for (int i = 0; i < content->numchildren; ++i) { > | ~ ^ ~~~~~~~~~~~~~~~~~~~~ > [..]/expat/fuzz/xml_lpm_fuzzer.cpp:413:24: error: comparison of integers of different signs: 'size_t' (aka 'unsigned long') and 'int' [-Werror,-Wsign-compare] > 413 | for (size_t i = 0; i < testcase.fail_allocations_size(); ++i) { > | ~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > [..]/expat/fuzz/xml_lpm_fuzzer.cpp:421:24: error: comparison of integers of different signs: 'size_t' (aka 'unsigned long') and 'int' [-Werror,-Wsign-compare] > 421 | for (size_t i = 0; i < testcase.actions_size(); ++i) { > | ~ ^ ~~~~~~~~~~~~~~~~~~~~~~~ --- expat/fuzz/xml_lpm_fuzzer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index bb108fbf..acd50333 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -154,7 +154,7 @@ static void TouchNodeAndRecurse(XML_Content* content) { assert(content->quant == XML_CQUANT_NONE || content->quant == XML_CQUANT_REP); assert(content->name == NULL); - for (int i = 0; i < content->numchildren; ++i) { + for (unsigned int i = 0; i < content->numchildren; ++i) { assert(content->children[i].type == XML_CTYPE_NAME); assert(content->children[i].quant == XML_CQUANT_NONE); assert(content->children[i].numchildren == 0); @@ -180,7 +180,7 @@ static void TouchNodeAndRecurse(XML_Content* content) { || (content->quant == XML_CQUANT_REP) || (content->quant == XML_CQUANT_PLUS)); assert(content->name == NULL); - for (int i = 0; i < content->numchildren; ++i) { + for (unsigned int i = 0; i < content->numchildren; ++i) { TouchNodeAndRecurse(&content->children[i]); } break; @@ -388,7 +388,7 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { g_allocation_count = 0; g_fail_allocations.clear(); - for (size_t i = 0; i < testcase.fail_allocations_size(); ++i) { + for (int i = 0; i < testcase.fail_allocations_size(); ++i) { g_fail_allocations.push_back(testcase.fail_allocations(i)); } @@ -396,7 +396,7 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { XML_Parser parser = XML_ParserCreate_MM(g_encoding, &memory_handling_suite, "|"); InitializeParser(parser); - for (size_t i = 0; i < testcase.actions_size(); ++i) { + for (int i = 0; i < testcase.actions_size(); ++i) { const auto& action = testcase.actions(i); switch (action.action_case()) { case xml_lpm_fuzzer::Action::kChunk: From b223d302cb3452ba93074017233dacb888001c2a Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 21:06:44 +0100 Subject: [PATCH 27/36] xml_lpm_fuzzer: Address warning -Wunused-parameter --- expat/fuzz/xml_lpm_fuzzer.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index acd50333..69c26a99 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -201,22 +201,27 @@ static void XMLCALL AttlistDeclHandler(void* userData, const XML_Char* elname, const XML_Char* attname, const XML_Char* atttype, const XML_Char* dflt, int isrequired) { + (void)userData; TouchString(elname); TouchString(attname); TouchString(atttype); TouchString(dflt); + (void)isrequired; } static void XMLCALL XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone) { + (void)userData; TouchString(version); TouchString(encoding); + (void)standalone; } static void XMLCALL StartElementHandler(void *userData, const XML_Char *name, const XML_Char **atts) { + (void)userData; TouchString(name); for (size_t i = 0; atts[i] != NULL; ++i) { TouchString(atts[i]); @@ -225,17 +230,20 @@ StartElementHandler(void *userData, const XML_Char *name, static void XMLCALL EndElementHandler(void *userData, const XML_Char *name) { + (void)userData; TouchString(name); } static void XMLCALL CharacterDataHandler(void* userData, const XML_Char* s, int len) { + (void)userData; TouchString(s, len); } static void XMLCALL ProcessingInstructionHandler(void* userData, const XML_Char* target, const XML_Char* data) { + (void)userData; TouchString(target); TouchString(data); } @@ -250,14 +258,17 @@ CommentHandler(void* userData, const XML_Char* data) { static void XMLCALL StartCdataSectionHandler(void* userData) { + (void)userData; } static void XMLCALL EndCdataSectionHandler(void* userData) { + (void)userData; } static void XMLCALL DefaultHandler(void* userData, const XML_Char* s, int len) { + (void)userData; TouchString(s, len); } @@ -265,13 +276,16 @@ static void XMLCALL StartDoctypeDeclHandler(void* userData, const XML_Char* doctypeName, const XML_Char* sysid, const XML_Char* pubid, int has_internal_subset) { + (void)userData; TouchString(doctypeName); TouchString(sysid); TouchString(pubid); + (void)has_internal_subset; } static void XMLCALL EndDoctypeDeclHandler(void* userData) { + (void)userData; } static void XMLCALL @@ -280,7 +294,9 @@ EntityDeclHandler(void *userData, const XML_Char *entityName, int value_length, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName) { + (void)userData; TouchString(entityName); + (void)is_parameter_entity; TouchString(value, value_length); TouchString(base); TouchString(systemId); @@ -292,6 +308,7 @@ static void XMLCALL NotationDeclHandler(void *userData, const XML_Char *notationName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { + (void)userData; TouchString(notationName); TouchString(base); TouchString(systemId); @@ -301,17 +318,20 @@ NotationDeclHandler(void *userData, const XML_Char *notationName, static void XMLCALL StartNamespaceDeclHandler(void *userData, const XML_Char *prefix, const XML_Char *uri) { + (void)userData; TouchString(prefix); TouchString(uri); } static void XMLCALL EndNamespaceDeclHandler(void *userData, const XML_Char *prefix) { + (void)userData; TouchString(prefix); } static int XMLCALL NotStandaloneHandler(void *userData) { + (void)userData; return XML_STATUS_OK; } @@ -339,13 +359,17 @@ ExternalEntityRefHandler(XML_Parser parser, const XML_Char *context, static void XMLCALL SkippedEntityHandler(void *userData, const XML_Char *entityName, int is_parameter_entity) { + (void)userData; TouchString(entityName); + (void)is_parameter_entity; } static int XMLCALL UnknownEncodingHandler(void *encodingHandlerData, const XML_Char *name, XML_Encoding *info) { + (void)encodingHandlerData; TouchString(name); + (void)info; return XML_STATUS_ERROR; } From 922e95a3933f4c74f1d0254a09ec2073c6b23415 Mon Sep 17 00:00:00 2001 From: "clang-format 19.1.2" Date: Sun, 2 Feb 2025 21:54:29 +0100 Subject: [PATCH 28/36] xml_lpm_fuzzer: Apply clang-format 19.1.2 --- expat/fuzz/xml_lpm_fuzzer.cpp | 254 +++++++++++++++++----------------- 1 file changed, 129 insertions(+), 125 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 69c26a99..a2982fc2 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -30,7 +30,7 @@ */ #if defined(NDEBUG) -# undef NDEBUG // because checks below rely on assert(...) +# undef NDEBUG // because checks below rely on assert(...) #endif #include @@ -41,42 +41,44 @@ #include "xml_lpm_fuzzer.pb.h" #include "src/libfuzzer/libfuzzer_macro.h" -static const char* g_encoding = nullptr; -static const char* g_external_entity = nullptr; +static const char *g_encoding = nullptr; +static const char *g_external_entity = nullptr; static size_t g_external_entity_size = 0; -void SetEncoding(const xml_lpm_fuzzer::Encoding& e) { +void +SetEncoding(const xml_lpm_fuzzer::Encoding &e) { switch (e) { - case xml_lpm_fuzzer::Encoding::UTF8: - g_encoding = "UTF-8"; - break; + case xml_lpm_fuzzer::Encoding::UTF8: + g_encoding = "UTF-8"; + break; - case xml_lpm_fuzzer::Encoding::UTF16: - g_encoding = "UTF-16"; - break; + case xml_lpm_fuzzer::Encoding::UTF16: + g_encoding = "UTF-16"; + break; - case xml_lpm_fuzzer::Encoding::ISO88591: - g_encoding = "ISO-8859-1"; - break; + case xml_lpm_fuzzer::Encoding::ISO88591: + g_encoding = "ISO-8859-1"; + break; - case xml_lpm_fuzzer::Encoding::ASCII: - g_encoding = "US-ASCII"; - break; + case xml_lpm_fuzzer::Encoding::ASCII: + g_encoding = "US-ASCII"; + break; - case xml_lpm_fuzzer::Encoding::NONE: - g_encoding = NULL; - break; + case xml_lpm_fuzzer::Encoding::NONE: + g_encoding = NULL; + break; - default: - g_encoding = "UNKNOWN"; - break; + default: + g_encoding = "UNKNOWN"; + break; } } static int g_allocation_count = 0; static std::vector g_fail_allocations = {}; -void* MallocHook(size_t size) { +void * +MallocHook(size_t size) { for (auto index : g_fail_allocations) { if (index == g_allocation_count) { return NULL; @@ -86,7 +88,8 @@ void* MallocHook(size_t size) { return malloc(size); } -void* ReallocHook(void* ptr, size_t size) { +void * +ReallocHook(void *ptr, size_t size) { for (auto index : g_fail_allocations) { if (index == g_allocation_count) { return NULL; @@ -96,20 +99,20 @@ void* ReallocHook(void* ptr, size_t size) { return realloc(ptr, size); } -void FreeHook(void* ptr) { +void +FreeHook(void *ptr) { free(ptr); } -XML_Memory_Handling_Suite memory_handling_suite = { - MallocHook, ReallocHook, FreeHook -}; +XML_Memory_Handling_Suite memory_handling_suite + = {MallocHook, ReallocHook, FreeHook}; void InitializeParser(XML_Parser parser); // We want a parse function that supports resumption, so that we can cover the // suspend/resume code. -enum XML_Status Parse(XML_Parser parser, const char* input, int input_len, - int is_final) { +enum XML_Status +Parse(XML_Parser parser, const char *input, int input_len, int is_final) { enum XML_Status status = XML_Parse(parser, input, input_len, is_final); while (status == XML_STATUS_SUSPENDED) { status = XML_ResumeParser(parser); @@ -124,8 +127,9 @@ enum XML_Status Parse(XML_Parser parser, const char* input, int input_len, // in terms of length/null-termination. no_optimize is used to ensure that the // compiler has to emit actual memory reads, instead of removing them. static volatile size_t no_optimize = 0; -static void TouchString(const XML_Char* ptr, int len=-1) { - if (!ptr) { +static void +TouchString(const XML_Char *ptr, int len = -1) { + if (! ptr) { return; } @@ -140,67 +144,68 @@ static void TouchString(const XML_Char* ptr, int len=-1) { } } -static void TouchNodeAndRecurse(XML_Content* content) { +static void +TouchNodeAndRecurse(XML_Content *content) { switch (content->type) { - case XML_CTYPE_EMPTY: - case XML_CTYPE_ANY: - assert(content->quant == XML_CQUANT_NONE); - assert(content->name == NULL); - assert(content->numchildren == 0); - assert(content->children == NULL); - break; + case XML_CTYPE_EMPTY: + case XML_CTYPE_ANY: + assert(content->quant == XML_CQUANT_NONE); + assert(content->name == NULL); + assert(content->numchildren == 0); + assert(content->children == NULL); + break; - case XML_CTYPE_MIXED: - assert(content->quant == XML_CQUANT_NONE - || content->quant == XML_CQUANT_REP); - assert(content->name == NULL); - for (unsigned int i = 0; i < content->numchildren; ++i) { - assert(content->children[i].type == XML_CTYPE_NAME); - assert(content->children[i].quant == XML_CQUANT_NONE); - assert(content->children[i].numchildren == 0); - assert(content->children[i].children == NULL); - TouchString(content->children[i].name); - } - break; + case XML_CTYPE_MIXED: + assert(content->quant == XML_CQUANT_NONE + || content->quant == XML_CQUANT_REP); + assert(content->name == NULL); + for (unsigned int i = 0; i < content->numchildren; ++i) { + assert(content->children[i].type == XML_CTYPE_NAME); + assert(content->children[i].quant == XML_CQUANT_NONE); + assert(content->children[i].numchildren == 0); + assert(content->children[i].children == NULL); + TouchString(content->children[i].name); + } + break; - case XML_CTYPE_NAME: - assert((content->quant == XML_CQUANT_NONE) - || (content->quant == XML_CQUANT_OPT) - || (content->quant == XML_CQUANT_REP) - || (content->quant == XML_CQUANT_PLUS)); - assert(content->numchildren == 0); - assert(content->children == NULL); - TouchString(content->name); - break; + case XML_CTYPE_NAME: + assert((content->quant == XML_CQUANT_NONE) + || (content->quant == XML_CQUANT_OPT) + || (content->quant == XML_CQUANT_REP) + || (content->quant == XML_CQUANT_PLUS)); + assert(content->numchildren == 0); + assert(content->children == NULL); + TouchString(content->name); + break; - case XML_CTYPE_CHOICE: - case XML_CTYPE_SEQ: - assert((content->quant == XML_CQUANT_NONE) - || (content->quant == XML_CQUANT_OPT) - || (content->quant == XML_CQUANT_REP) - || (content->quant == XML_CQUANT_PLUS)); - assert(content->name == NULL); - for (unsigned int i = 0; i < content->numchildren; ++i) { - TouchNodeAndRecurse(&content->children[i]); - } - break; + case XML_CTYPE_CHOICE: + case XML_CTYPE_SEQ: + assert((content->quant == XML_CQUANT_NONE) + || (content->quant == XML_CQUANT_OPT) + || (content->quant == XML_CQUANT_REP) + || (content->quant == XML_CQUANT_PLUS)); + assert(content->name == NULL); + for (unsigned int i = 0; i < content->numchildren; ++i) { + TouchNodeAndRecurse(&content->children[i]); + } + break; - default: - assert(false); + default: + assert(false); } } static void XMLCALL -ElementDeclHandler(void* userData, const XML_Char* name, XML_Content* model) { +ElementDeclHandler(void *userData, const XML_Char *name, XML_Content *model) { TouchString(name); TouchNodeAndRecurse(model); XML_FreeContentModel((XML_Parser)userData, model); } static void XMLCALL -AttlistDeclHandler(void* userData, const XML_Char* elname, - const XML_Char* attname, const XML_Char* atttype, - const XML_Char* dflt, int isrequired) { +AttlistDeclHandler(void *userData, const XML_Char *elname, + const XML_Char *attname, const XML_Char *atttype, + const XML_Char *dflt, int isrequired) { (void)userData; TouchString(elname); TouchString(attname); @@ -210,8 +215,8 @@ AttlistDeclHandler(void* userData, const XML_Char* elname, } static void XMLCALL -XmlDeclHandler(void* userData, const XML_Char* version, - const XML_Char* encoding, int standalone) { +XmlDeclHandler(void *userData, const XML_Char *version, + const XML_Char *encoding, int standalone) { (void)userData; TouchString(version); TouchString(encoding); @@ -235,21 +240,21 @@ EndElementHandler(void *userData, const XML_Char *name) { } static void XMLCALL -CharacterDataHandler(void* userData, const XML_Char* s, int len) { +CharacterDataHandler(void *userData, const XML_Char *s, int len) { (void)userData; TouchString(s, len); } static void XMLCALL -ProcessingInstructionHandler(void* userData, const XML_Char* target, - const XML_Char* data) { +ProcessingInstructionHandler(void *userData, const XML_Char *target, + const XML_Char *data) { (void)userData; TouchString(target); TouchString(data); } static void XMLCALL -CommentHandler(void* userData, const XML_Char* data) { +CommentHandler(void *userData, const XML_Char *data) { TouchString(data); // Use the comment handler to trigger parser suspend, so that we can get // coverage of that code. @@ -257,24 +262,24 @@ CommentHandler(void* userData, const XML_Char* data) { } static void XMLCALL -StartCdataSectionHandler(void* userData) { +StartCdataSectionHandler(void *userData) { (void)userData; } static void XMLCALL -EndCdataSectionHandler(void* userData) { +EndCdataSectionHandler(void *userData) { (void)userData; } static void XMLCALL -DefaultHandler(void* userData, const XML_Char* s, int len) { +DefaultHandler(void *userData, const XML_Char *s, int len) { (void)userData; TouchString(s, len); } static void XMLCALL -StartDoctypeDeclHandler(void* userData, const XML_Char* doctypeName, - const XML_Char* sysid, const XML_Char* pubid, +StartDoctypeDeclHandler(void *userData, const XML_Char *doctypeName, + const XML_Char *sysid, const XML_Char *pubid, int has_internal_subset) { (void)userData; TouchString(doctypeName); @@ -284,7 +289,7 @@ StartDoctypeDeclHandler(void* userData, const XML_Char* doctypeName, } static void XMLCALL -EndDoctypeDeclHandler(void* userData) { +EndDoctypeDeclHandler(void *userData) { (void)userData; } @@ -346,10 +351,9 @@ ExternalEntityRefHandler(XML_Parser parser, const XML_Char *context, TouchString(publicId); if (g_external_entity) { - XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, context, - g_encoding); - rc = Parse(ext_parser, g_external_entity, - g_external_entity_size, 1); + XML_Parser ext_parser + = XML_ExternalEntityParserCreate(parser, context, g_encoding); + rc = Parse(ext_parser, g_external_entity, g_external_entity_size, 1); XML_ParserFree(ext_parser); } @@ -373,8 +377,9 @@ UnknownEncodingHandler(void *encodingHandlerData, const XML_Char *name, return XML_STATUS_ERROR; } -void InitializeParser(XML_Parser parser) { - XML_SetUserData(parser, (void*)parser); +void +InitializeParser(XML_Parser parser) { + XML_SetUserData(parser, (void *)parser); XML_SetHashSalt(parser, 0x41414141); XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); @@ -400,13 +405,13 @@ void InitializeParser(XML_Parser parser) { XML_SetNotStandaloneHandler(parser, NotStandaloneHandler); XML_SetExternalEntityRefHandler(parser, ExternalEntityRefHandler); XML_SetSkippedEntityHandler(parser, SkippedEntityHandler); - XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, (void*)parser); + XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, (void *)parser); } -DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { +DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase &testcase) { g_external_entity = nullptr; - if (!testcase.actions_size()) { + if (! testcase.actions_size()) { return; } @@ -417,41 +422,40 @@ DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase& testcase) { } SetEncoding(testcase.encoding()); - XML_Parser parser = XML_ParserCreate_MM(g_encoding, &memory_handling_suite, "|"); + XML_Parser parser + = XML_ParserCreate_MM(g_encoding, &memory_handling_suite, "|"); InitializeParser(parser); for (int i = 0; i < testcase.actions_size(); ++i) { - const auto& action = testcase.actions(i); + const auto &action = testcase.actions(i); switch (action.action_case()) { - case xml_lpm_fuzzer::Action::kChunk: - if (XML_STATUS_ERROR == Parse(parser, - action.chunk().data(), - action.chunk().size(), 0)) { - // Force a reset after parse error. - XML_ParserReset(parser, g_encoding); - InitializeParser(parser); - } - break; - - case xml_lpm_fuzzer::Action::kLastChunk: - Parse(parser, action.last_chunk().data(), - action.last_chunk().size(), 1); + case xml_lpm_fuzzer::Action::kChunk: + if (XML_STATUS_ERROR + == Parse(parser, action.chunk().data(), action.chunk().size(), 0)) { + // Force a reset after parse error. XML_ParserReset(parser, g_encoding); InitializeParser(parser); - break; + } + break; - case xml_lpm_fuzzer::Action::kReset: - XML_ParserReset(parser, g_encoding); - InitializeParser(parser); - break; + case xml_lpm_fuzzer::Action::kLastChunk: + Parse(parser, action.last_chunk().data(), action.last_chunk().size(), 1); + XML_ParserReset(parser, g_encoding); + InitializeParser(parser); + break; - case xml_lpm_fuzzer::Action::kExternalEntity: - g_external_entity = action.external_entity().data(); - g_external_entity_size = action.external_entity().size(); - break; + case xml_lpm_fuzzer::Action::kReset: + XML_ParserReset(parser, g_encoding); + InitializeParser(parser); + break; - default: - break; + case xml_lpm_fuzzer::Action::kExternalEntity: + g_external_entity = action.external_entity().data(); + g_external_entity_size = action.external_entity().size(); + break; + + default: + break; } } From 0497f35d04a0e0ffbc8b1a168b37a95a753b55a4 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 16:50:59 +0100 Subject: [PATCH 29/36] fuzzing.yml: Install build dependencies of xml_lpm_fuzzer --- .github/workflows/fuzzing.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index 86a5a661..d38fec57 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -59,6 +59,15 @@ jobs: llvm-19 echo /usr/lib/llvm-19/bin >>"${GITHUB_PATH}" + - name: Install build dependencies + run: |- + set -x + sudo apt-get install --yes --no-install-recommends -V \ + libabsl-dev \ + liblzma-dev \ + libprotobuf-dev \ + protobuf-compiler + - name: Build Expat fuzzers run: | set -x -o pipefail From 8d7f50bc6e35185973d19da4c97d67f10e23c038 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 17:08:20 +0100 Subject: [PATCH 30/36] fuzzing.yml: Pass C++ compiler and compile flags to CMake --- .github/workflows/fuzzing.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index d38fec57..10a27902 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -88,7 +88,8 @@ jobs: # Tune compilation of fuzzers to use Clang with ASan and UBSan -DCMAKE_C_COMPILER=clang - -DCMAKE_C_FLAGS='-Wall -Wextra -pedantic -O1 -g -fsanitize=address,undefined -fno-sanitize-recover=all -fno-omit-frame-pointer -fno-common' + -DCMAKE_CXX_COMPILER=clang++ + -DCMAKE_{C,CXX}_FLAGS='-Wall -Wextra -pedantic -O1 -g -fsanitize=address,undefined -fno-sanitize-recover=all -fno-omit-frame-pointer -fno-common' -DCMAKE_{EXE,MODULE,SHARED}_LINKER_FLAGS='-g -fsanitize=address,undefined' -DEXPAT_WARNINGS_AS_ERRORS=ON ) From 69a7a7090dff1750dfe006ed2f837b8b3ffc18e4 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 17:25:54 +0100 Subject: [PATCH 31/36] fuzzing.yml: Bump to Ubuntu 24.04 Due to broken(?) CMake in Ubuntu 22.04, symptom was: > CMake Error: Error required internal CMake variable not set, cmake may not be built correctly. > Missing variable is: > CMAKE_CXX_LINK_EXECUTABLE > CMake Generate step failed. Build files cannot be regenerated correctly. --- .github/workflows/fuzzing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index 10a27902..bfd69885 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -42,7 +42,7 @@ permissions: jobs: run_fuzzers: name: Run fuzzing regression tests - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 From 57d6e4ad56702d7f3243ba3fccff0598ca866ab0 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 21:48:41 +0100 Subject: [PATCH 32/36] fuzzing.yml: Assert xml_lpm_fuzzer executability .. while it is not being using to run any regression tests --- .github/workflows/fuzzing.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index bfd69885..0c6adf18 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -96,6 +96,8 @@ jobs: cmake "${args[@]}" -S . -B build make -C build VERBOSE=1 -j$(nproc) + ./build/fuzz/xml_lpm_fuzzer -help=1 + - name: Download and extract Expat fuzzing corpora run: |- set -x From 1ed7be5bf714fa310dcc9208943d7ce93ab9d615 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sun, 2 Feb 2025 22:32:45 +0100 Subject: [PATCH 33/36] linux.yml: Drop -DEXPAT_BUILD_FUZZERS=ON case in favor of fuzzing.yml --- .github/workflows/linux.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 58989fad..2bbca180 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -52,8 +52,6 @@ jobs: - MODE: distcheck - MODE: qa-sh FLAT_ENV: CC=clang CXX=clang++ LD=clang++ QA_SANITIZER=address - - MODE: cmake-oos - FLAT_ENV: CMAKE_ARGS="-DEXPAT_ATTR_INFO=ON -DEXPAT_BUILD_FUZZERS=ON -DCMAKE_C_FLAGS=-fsanitize=address -DCMAKE_CXX_FLAGS=-fsanitize=address -DCMAKE_EXE_LINKER_FLAGS=-fsanitize=address -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++" - MODE: qa-sh FLAT_ENV: CC=clang CXX=clang++ LD=clang++ QA_SANITIZER=address CMAKE_ARGS=-DEXPAT_ATTR_INFO=ON - MODE: qa-sh From 2a615bc3c553db117097b11393b32bfc33169fcb Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 3 Feb 2025 01:23:41 +0100 Subject: [PATCH 34/36] xml_lpm_fuzzer: Unstuck MallocHook and ReallocHook .. so that they fail single allocations, not all allocations after a certain point. Previously fail_allocations of [6, 2, 20] worked the same way fail_allocations of [2], likely by accidently. --- expat/fuzz/xml_lpm_fuzzer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index a2982fc2..87c99be1 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -79,23 +79,23 @@ static std::vector g_fail_allocations = {}; void * MallocHook(size_t size) { + g_allocation_count += 1; for (auto index : g_fail_allocations) { if (index == g_allocation_count) { return NULL; } } - g_allocation_count += 1; return malloc(size); } void * ReallocHook(void *ptr, size_t size) { + g_allocation_count += 1; for (auto index : g_fail_allocations) { if (index == g_allocation_count) { return NULL; } } - g_allocation_count += 1; return realloc(ptr, size); } From c18e90f92731d6b5e793792231c890afc80d8f2c Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 3 Feb 2025 01:33:53 +0100 Subject: [PATCH 35/36] xml_lpm_fuzzer: Use common attribution format --- expat/fuzz/xml_lpm_fuzzer.cpp | 2 +- expat/fuzz/xml_lpm_fuzzer.proto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 87c99be1..737ad3c2 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -6,7 +6,7 @@ \___/_/\_\ .__/ \__,_|\__| |_| XML parser - Copyright (c) 2022 Google LLC + Copyright (c) 2022 Mark Brand Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining diff --git a/expat/fuzz/xml_lpm_fuzzer.proto b/expat/fuzz/xml_lpm_fuzzer.proto index 3bd3a5b3..f4c11f79 100644 --- a/expat/fuzz/xml_lpm_fuzzer.proto +++ b/expat/fuzz/xml_lpm_fuzzer.proto @@ -6,7 +6,7 @@ \___/_/\_\ .__/ \__,_|\__| |_| XML parser - Copyright (c) 2022 Google LLC + Copyright (c) 2022 Mark Brand Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining From a0b8957db2f77c83991029b32f814e0023f2e338 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 3 Feb 2025 01:37:51 +0100 Subject: [PATCH 36/36] Sync file headers --- .github/workflows/linux.yml | 2 +- expat/CMakeLists.txt | 1 + expat/fuzz/xml_lpm_fuzzer.cpp | 1 + expat/fuzz/xml_lpm_fuzzer.proto | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 2bbca180..e92fc5af 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -5,7 +5,7 @@ # \___/_/\_\ .__/ \__,_|\__| # |_| XML parser # -# Copyright (c) 2021-2024 Sebastian Pipping +# Copyright (c) 2021-2025 Sebastian Pipping # Copyright (c) 2023 Joyce Brum # Copyright (c) 2023 Hanno Böck # Copyright (c) 2024 Dag-Erling Smørgrav diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index 7ae338e6..1e6dcdb7 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -30,6 +30,7 @@ # Copyright (c) 2020 Thomas Beutlich # Copyright (c) 2021 Alex Richardson # Copyright (c) 2022 Johnny Jazeix +# Copyright (c) 2022 Mark Brand # Copyright (c) 2022 David Faure # Unlike most of Expat, # this file is copyrighted under the BSD-license for buildsystem files of KDE. diff --git a/expat/fuzz/xml_lpm_fuzzer.cpp b/expat/fuzz/xml_lpm_fuzzer.cpp index 737ad3c2..f52ea7b2 100644 --- a/expat/fuzz/xml_lpm_fuzzer.cpp +++ b/expat/fuzz/xml_lpm_fuzzer.cpp @@ -7,6 +7,7 @@ |_| XML parser Copyright (c) 2022 Mark Brand + Copyright (c) 2025 Sebastian Pipping Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining diff --git a/expat/fuzz/xml_lpm_fuzzer.proto b/expat/fuzz/xml_lpm_fuzzer.proto index f4c11f79..ddc4e958 100644 --- a/expat/fuzz/xml_lpm_fuzzer.proto +++ b/expat/fuzz/xml_lpm_fuzzer.proto @@ -7,6 +7,7 @@ |_| XML parser Copyright (c) 2022 Mark Brand + Copyright (c) 2025 Sebastian Pipping Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining