From 29eddcae5f85bbf9e9151924e24add7358133f66 Mon Sep 17 00:00:00 2001 From: Mitch Phillips <31459023+hctim@users.noreply.github.com> Date: Wed, 28 Aug 2019 03:57:57 -0700 Subject: [PATCH] Add XML fuzzers to libexpat upstream. (#308) --- expat/CMakeLists.txt | 35 ++++++++++++++++ expat/fuzz/xml_parse_fuzzer.c | 59 +++++++++++++++++++++++++++ expat/fuzz/xml_parsebuffer_fuzzer.c | 63 +++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 expat/fuzz/xml_parse_fuzzer.c create mode 100644 expat/fuzz/xml_parsebuffer_fuzzer.c diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index 08232245..546be104 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -45,6 +45,7 @@ option(BUILD_examples "build the examples for expat library" ON) option(BUILD_tests "build the tests for expat library" ON) option(BUILD_shared "build a shared expat library" ON) option(BUILD_doc "build man page for xmlwf" ${BUILD_doc_default}) +option(BUILD_fuzzers "build fuzzers for the expat library" OFF) option(USE_libbsd "utilize libbsd (for arc4random_buf)" OFF) option(INSTALL "install expat files in cmake install target" ON) set(XML_CONTEXT_BYTES 1024 CACHE STRING "Define to specify how much context to retain around the current parse point") @@ -324,6 +325,40 @@ if(BUILD_tests) add_test(runtestspp tests/runtestspp) endif(BUILD_tests) +if(BUILD_fuzzers) + if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + message(SEND_ERROR + "Building fuzz targets without clang is not supported. Please set " + "-DCMAKE_C_COMPILER=clang.") + endif() + + string(FIND "${CMAKE_EXE_LINKER_FLAGS}" "-fsanitize" sanitizer_present) + if(${sanitizer_present} EQUAL "-1") + message(WARNING + "There was no sanitizer present when building the fuzz targets. " + "This is likely in error - consider adding " + "-DCMAKE_C_FLAGS='-fsanitize=' and " + "-DCMAKE_EXE_LINKER_FLAGS='-fsanitize=' to your cmake " + "execution.") + endif() + + set(encoding_types UTF-16 UTF-8 ISO-8859-1 US-ASCII UTF-16BE UTF-16LE) + set(fuzz_targets xml_parse_fuzzer xml_parsebuffer_fuzzer) + + foreach(fuzz_target ${fuzz_targets}) + foreach(encoding_type ${encoding_types}) + set(target_name ${fuzz_target}_${encoding_type}) + add_executable(${target_name} fuzz/${fuzz_target}.c ${expat_SRCS}) + target_compile_definitions(${target_name} + PRIVATE ENCODING_FOR_FUZZING=${encoding_type}) + target_compile_options(${target_name} PRIVATE -fsanitize=fuzzer-no-link) + target_link_options(${target_name} PRIVATE -fsanitize=fuzzer) + set_property( + TARGET ${target_name} PROPERTY RUNTIME_OUTPUT_DIRECTORY fuzz) + endforeach() + endforeach() +endif(BUILD_fuzzers) + # # Summary # diff --git a/expat/fuzz/xml_parse_fuzzer.c b/expat/fuzz/xml_parse_fuzzer.c new file mode 100644 index 00000000..81dcee19 --- /dev/null +++ b/expat/fuzz/xml_parse_fuzzer.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "expat.h" +#include "siphash.h" + +// Macros to convert preprocessor macros to string literals. See +// https://gcc.gnu.org/onlinedocs/gcc-3.4.3/cpp/Stringification.html +#define xstr(s) str(s) +#define str(s) #s + +// The encoder type that we wish to fuzz should come from the compile-time +// definition `ENCODING_FOR_FUZZING`. This allows us to have a separate fuzzer +// binary for +#ifndef ENCODING_FOR_FUZZING +# error "ENCODING_FOR_FUZZING was not provided to this fuzz target." +#endif + +// 16-byte determinstic hash key. +static unsigned char hash_key[16] = "FUZZING IS FUN!"; + +static void XMLCALL +start(void *userData, const XML_Char *name, const XML_Char **atts) { +} +static void XMLCALL +end(void *userData, const XML_Char *name) { +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + XML_Parser p = XML_ParserCreate(xstr(ENCODING_FOR_FUZZING)); + assert(p); + + // Set the hash salt using siphash to generate a deterministic hash. + struct sipkey *key = sip_keyof(hash_key); + XML_SetHashSalt(p, (unsigned long)siphash24(data, size, key)); + + XML_SetElementHandler(p, start, end); + XML_Parse(p, (const XML_Char *)data, size, 0); + XML_Parse(p, (const XML_Char *)data, size, 1); + XML_ParserFree(p); + return 0; +} diff --git a/expat/fuzz/xml_parsebuffer_fuzzer.c b/expat/fuzz/xml_parsebuffer_fuzzer.c new file mode 100644 index 00000000..aa51e039 --- /dev/null +++ b/expat/fuzz/xml_parsebuffer_fuzzer.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "expat.h" +#include "siphash.h" + +// Macros to convert preprocessor macros to string literals. See +// https://gcc.gnu.org/onlinedocs/gcc-3.4.3/cpp/Stringification.html +#define xstr(s) str(s) +#define str(s) #s + +// The encoder type that we wish to fuzz should come from the compile-time +// definition `ENCODING_FOR_FUZZING`. This allows us to have a separate fuzzer +// binary for +#ifndef ENCODING_FOR_FUZZING +# error "ENCODING_FOR_FUZZING was not provided to this fuzz target." +#endif + +// 16-byte determinstic hash key. +static unsigned char hash_key[16] = "FUZZING IS FUN!"; + +static void XMLCALL +start(void *userData, const XML_Char *name, const XML_Char **atts) { +} +static void XMLCALL +end(void *userData, const XML_Char *name) { +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + XML_Parser p = XML_ParserCreate(xstr(ENCODING_FOR_FUZZING)); + assert(p); + XML_SetElementHandler(p, start, end); + + // Set the hash salt using siphash to generate a deterministic hash. + struct sipkey *key = sip_keyof(hash_key); + XML_SetHashSalt(p, (unsigned long)siphash24(data, size, key)); + + void *buf = XML_GetBuffer(p, size); + assert(buf); + + memcpy(buf, data, size); + XML_ParseBuffer(p, size, size == 0); + XML_ParserFree(p); + return 0; +}