diff --git a/Makefile b/Makefile index f9b26d6..500675c 100644 --- a/Makefile +++ b/Makefile @@ -68,10 +68,9 @@ test: $(EXECUTABLE) ./$(EXECUTABLE) endif -fuzz: - @mkdir -p $(BUILD) - $(AFL)/afl-clang++ tests/fuzz_parse.cpp tests/allocator.cpp src/pugixml.cpp $(CXXFLAGS) -o $(BUILD)/fuzz_parse - $(AFL)/afl-fuzz -i tests/data_fuzz_parse -o $(BUILD)/fuzz_parse_out -x $(AFL)/testcases/_extras/xml/ -- $(BUILD)/fuzz_parse @@ +fuzz_%: $(BUILD)/fuzz_% + @mkdir -p build/$@ + $< build/$@ tests/data_$* -max_len=1024 -dict=tests/fuzz_$*.dict clean: rm -rf $(BUILD) @@ -87,6 +86,10 @@ build/pugixml-%: .FORCE | $(RELEASE) $(EXECUTABLE): $(OBJECTS) $(CXX) $(OBJECTS) $(LDFLAGS) -o $@ +$(BUILD)/fuzz_%: tests/fuzz_%.cpp src/pugixml.cpp + @mkdir -p $(BUILD) + clang++ $(CXXFLAGS) -fsanitize=address -fsanitize-coverage=trace-pc-guard $^ libFuzzer.a -o $@ + $(BUILD)/%.o: % @mkdir -p $(dir $@) $(CXX) $< $(CXXFLAGS) -c -MMD -MP -o $@ diff --git a/tests/data_fuzz_xpath/basic.xpath b/tests/data_fuzz_xpath/basic.xpath new file mode 100644 index 0000000..ccbaf23 --- /dev/null +++ b/tests/data_fuzz_xpath/basic.xpath @@ -0,0 +1 @@ +a/b/c \ No newline at end of file diff --git a/tests/data_fuzz_xpath/functions.xpath b/tests/data_fuzz_xpath/functions.xpath new file mode 100644 index 0000000..ec24b4f --- /dev/null +++ b/tests/data_fuzz_xpath/functions.xpath @@ -0,0 +1 @@ +sum(nodes) + round(concat(//a[translate(@id, 'abc', '012')])) diff --git a/tests/data_fuzz_xpath/math.xpath b/tests/data_fuzz_xpath/math.xpath new file mode 100644 index 0000000..7f6e968 --- /dev/null +++ b/tests/data_fuzz_xpath/math.xpath @@ -0,0 +1 @@ +1+2*3 div 4 mod 5-6 \ No newline at end of file diff --git a/tests/data_fuzz_xpath/path.xpath b/tests/data_fuzz_xpath/path.xpath new file mode 100644 index 0000000..82cace9 --- /dev/null +++ b/tests/data_fuzz_xpath/path.xpath @@ -0,0 +1 @@ +@*/ancestor::*/near-north/*[4]/@*/preceding::text() \ No newline at end of file diff --git a/tests/data_fuzz_xpath/predicate.xpath b/tests/data_fuzz_xpath/predicate.xpath new file mode 100644 index 0000000..7161d55 --- /dev/null +++ b/tests/data_fuzz_xpath/predicate.xpath @@ -0,0 +1 @@ +library/nodes[@id=12]/element[@type='translate'][1] \ No newline at end of file diff --git a/tests/fuzz_parse.cpp b/tests/fuzz_parse.cpp index e758196..94c610a 100644 --- a/tests/fuzz_parse.cpp +++ b/tests/fuzz_parse.cpp @@ -1,16 +1,14 @@ #include "../src/pugixml.hpp" -#include "allocator.hpp" -int main(int argc, const char** argv) +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - pugi::set_memory_management_functions(memory_allocate, memory_deallocate); - pugi::xml_document doc; - for (int i = 1; i < argc; ++i) - { - doc.load_file(argv[i]); - doc.load_file(argv[i], pugi::parse_minimal); - doc.load_file(argv[i], pugi::parse_full); - } + doc.load_buffer(Data, Size); + doc.load_buffer(Data, Size, pugi::parse_minimal); + doc.load_buffer(Data, Size, pugi::parse_full); + + return 0; } diff --git a/tests/fuzz_parse.dict b/tests/fuzz_parse.dict new file mode 100644 index 0000000..b1a0067 --- /dev/null +++ b/tests/fuzz_parse.dict @@ -0,0 +1,72 @@ +# +# AFL dictionary for XML +# ---------------------- +# +# Several basic syntax elements and attributes, modeled on libxml2. +# +# Created by Michal Zalewski +# + +attr_encoding=" encoding=\"1\"" +attr_generic=" a=\"1\"" +attr_href=" href=\"1\"" +attr_standalone=" standalone=\"no\"" +attr_version=" version=\"1\"" +attr_xml_base=" xml:base=\"1\"" +attr_xml_id=" xml:id=\"1\"" +attr_xml_lang=" xml:lang=\"1\"" +attr_xml_space=" xml:space=\"1\"" +attr_xmlns=" xmlns=\"1\"" + +entity_builtin="<" +entity_decimal="" +entity_external="&a;" +entity_hex="" + +string_any="ANY" +string_brackets="[]" +string_cdata="CDATA" +string_col_fallback=":fallback" +string_col_generic=":a" +string_col_include=":include" +string_dashes="--" +string_empty="EMPTY" +string_empty_dblquotes="\"\"" +string_empty_quotes="''" +string_entities="ENTITIES" +string_entity="ENTITY" +string_fixed="#FIXED" +string_id="ID" +string_idref="IDREF" +string_idrefs="IDREFS" +string_implied="#IMPLIED" +string_nmtoken="NMTOKEN" +string_nmtokens="NMTOKENS" +string_notation="NOTATION" +string_parentheses="()" +string_pcdata="#PCDATA" +string_percent="%a" +string_public="PUBLIC" +string_required="#REQUIRED" +string_schema=":schema" +string_system="SYSTEM" +string_ucs4="UCS-4" +string_utf16="UTF-16" +string_utf8="UTF-8" +string_xmlns="xmlns:" + +tag_attlist="" +tag_doctype="" +tag_open_close="" +tag_open_exclamation="" +tag_xml_q="" diff --git a/tests/fuzz_setup.sh b/tests/fuzz_setup.sh new file mode 100755 index 0000000..05a40cb --- /dev/null +++ b/tests/fuzz_setup.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +sudo apt-get --yes install subversion screen gcc g++ cmake ninja-build golang autoconf libtool apache2 python-dev pkg-config zlib1g-dev libgcrypt11-dev + +cd clang +git clone https://chromium.googlesource.com/chromium/src/tools/clang +cd .. +clang/clang/scripts/update.py +sudo cp -rf third_party/llvm-build/Release+Asserts/lib/* /usr/local/lib/ +sudo cp -rf third_party/llvm-build/Release+Asserts/bin/* /usr/local/bin + +svn co http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer +Fuzzer/build.sh diff --git a/tests/fuzz_xpath.cpp b/tests/fuzz_xpath.cpp new file mode 100644 index 0000000..c7ff4cd --- /dev/null +++ b/tests/fuzz_xpath.cpp @@ -0,0 +1,26 @@ +#include "../src/pugixml.hpp" + +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) +{ + char* text = new char[Size + 1]; + memcpy(text, Data, Size); + text[Size] = 0; + +#ifdef PUGIXML_NO_EXCEPTIONS + pugi::xpath_query q(text); +#else + try + { + pugi::xpath_query q(text); + } + catch (pugi::xpath_exception&) + { + } +#endif + + delete[] text; + return 0; +} diff --git a/tests/fuzz_xpath.dict b/tests/fuzz_xpath.dict new file mode 100644 index 0000000..c469f6e --- /dev/null +++ b/tests/fuzz_xpath.dict @@ -0,0 +1,72 @@ +"boolean" +"count" +"contains" +"concat" +"ceiling" +"false" +"floor" +"id" +"last" +"lang" +"local-name" +"name" +"namespace-uri" +"normalize-space" +"not" +"number" +"position" +"round" +"string" +"string-length" +"starts-with" +"substring-before" +"substring-after" +"substring" +"sum" +"translate" +"true" +"ancestor" +"ancestor-or-self" +"attribute" +"child" +"descendant" +"descendant-or-self" +"following" +"following-sibling" +"namespace" +"parent" +"preceding" +"preceding-sibling" +"self" +"comment" +"node" +"processing-instruction" +"text" +"or" +"and" +"div" +"mod" +">" +">=" +"<" +"<=" +"!" +"!=" +"=" +"+" +"-" +"*" +"|" +"$" +"(" +")" +"[" +"]" +"," +"//" +"/" +".." +"." +"@" +"::" +":"