diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am index bc5ee9ab..0d1920d7 100644 --- a/fuzz/Makefile.am +++ b/fuzz/Makefile.am @@ -1,5 +1,5 @@ AUTOMAKE_OPTIONS = -Wno-syntax -EXTRA_PROGRAMS = genSeed html regexp schema uri xml xpath +EXTRA_PROGRAMS = genSeed html regexp schema uri xinclude xml xpath check_PROGRAMS = testFuzzer EXTRA_DIST = html.dict regexp.dict schema.dict xml.dict xpath.dict \ static_seed/uri static_seed/regexp fuzz.h @@ -19,8 +19,6 @@ XML_SEED_CORPUS_SRC = \ '$(top_srcdir)/test/valid/*.xml' \ '$(top_srcdir)/test/VC/*' \ '$(top_srcdir)/test/VCM/*' \ - '$(top_srcdir)/test/XInclude/docs/*' \ - '$(top_srcdir)/test/XInclude/without-reader/*' \ '$(top_srcdir)/test/xmlid/*' testFuzzer_SOURCES = testFuzzer.c fuzz.c @@ -28,7 +26,7 @@ testFuzzer_SOURCES = testFuzzer.c fuzz.c .PHONY: corpus clean-corpus corpus: seed/html.stamp seed/regexp.stamp seed/schema.stamp seed/uri.stamp \ - seed/xml.stamp seed/xpath.stamp + seed/xinclude.stamp seed/xml.stamp seed/xpath.stamp check-local: corpus ./testFuzzer$(EXEEXT) @@ -60,6 +58,26 @@ fuzz-xml: xml$(EXEEXT) seed/xml.stamp -timeout=20 \ corpus/xml seed/xml +# XInclude fuzzer + +seed/xinclude.stamp: genSeed$(EXEEXT) + @mkdir -p seed/xinclude + ./genSeed$(EXEEXT) xinclude \ + '$(top_srcdir)/test/XInclude/docs/*' \ + '$(top_srcdir)/test/XInclude/without-reader/*' + @touch seed/xinclude.stamp + +xinclude_SOURCES = xinclude.c fuzz.c +xinclude_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer + +fuzz-xinclude: xinclude$(EXEEXT) seed/xinclude.stamp + @mkdir -p corpus/xinclude + ./xinclude$(EXEEXT) \ + -dict=xml.dict \ + -max_len=$(XML_MAX_LEN) \ + -timeout=20 \ + corpus/xinclude seed/xinclude + # HTML fuzzer seed/html.stamp: genSeed$(EXEEXT) diff --git a/fuzz/fuzz.h b/fuzz/fuzz.h index a51b3987..e51dc7a9 100644 --- a/fuzz/fuzz.h +++ b/fuzz/fuzz.h @@ -27,9 +27,12 @@ extern "C" { #if 1 #define HAVE_URI_FUZZER #endif +#if defined(LIBXML_XINCLUDE_ENABLED) && \ + defined(LIBXML_READER_ENABLED) + #define HAVE_XINCLUDE_FUZZER +#endif #if defined(LIBXML_OUTPUT_ENABLED) && \ - defined(LIBXML_READER_ENABLED) && \ - defined(LIBXML_XINCLUDE_ENABLED) + defined(LIBXML_READER_ENABLED) #define HAVE_XML_FUZZER #endif #if defined(LIBXML_XPATH_ENABLED) diff --git a/fuzz/genSeed.c b/fuzz/genSeed.c index dc1c1449..0a78fdf5 100644 --- a/fuzz/genSeed.c +++ b/fuzz/genSeed.c @@ -406,6 +406,11 @@ main(int argc, const char **argv) { #ifdef HAVE_SCHEMA_FUZZER processArg = processPattern; globalData.processFile = processSchema; +#endif + } else if (strcmp(fuzzer, "xinclude") == 0) { +#ifdef HAVE_XINCLUDE_FUZZER + processArg = processPattern; + globalData.processFile = processXml; #endif } else if (strcmp(fuzzer, "xml") == 0) { #ifdef HAVE_XML_FUZZER diff --git a/fuzz/testFuzzer.c b/fuzz/testFuzzer.c index d14b29be..fb791d99 100644 --- a/fuzz/testFuzzer.c +++ b/fuzz/testFuzzer.c @@ -52,6 +52,16 @@ int fuzzUri(const char *data, size_t size); #undef LLVMFuzzerTestOneInput #endif +#ifdef HAVE_XINCLUDE_FUZZER +int fuzzXIncludeInit(int *argc, char ***argv); +int fuzzXInclude(const char *data, size_t size); +#define LLVMFuzzerInitialize fuzzXIncludeInit +#define LLVMFuzzerTestOneInput fuzzXInclude +#include "xinclude.c" +#undef LLVMFuzzerInitialize +#undef LLVMFuzzerTestOneInput +#endif + #ifdef HAVE_XML_FUZZER int fuzzXmlInit(int *argc, char ***argv); int fuzzXml(const char *data, size_t size); @@ -183,6 +193,10 @@ main(void) { if (testFuzzer(NULL, fuzzUri, "seed/uri/*") != 0) ret = 1; #endif +#ifdef HAVE_XINCLUDE_FUZZER + if (testFuzzer(fuzzXIncludeInit, fuzzXInclude, "seed/xinclude/*") != 0) + ret = 1; +#endif #ifdef HAVE_XML_FUZZER if (testFuzzer(fuzzXmlInit, fuzzXml, "seed/xml/*") != 0) ret = 1; diff --git a/fuzz/xinclude.c b/fuzz/xinclude.c new file mode 100644 index 00000000..b86e21b2 --- /dev/null +++ b/fuzz/xinclude.c @@ -0,0 +1,73 @@ +/* + * xinclude.c: a libFuzzer target to test the XInclude engine. + * + * See Copyright for the status of this software. + */ + +#include +#include +#include +#include +#include +#include +#include "fuzz.h" + +int +LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED, + char ***argv ATTRIBUTE_UNUSED) { + xmlInitParser(); +#ifdef LIBXML_CATALOG_ENABLED + xmlInitializeCatalog(); +#endif + xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc); + xmlSetExternalEntityLoader(xmlFuzzEntityLoader); + + return 0; +} + +int +LLVMFuzzerTestOneInput(const char *data, size_t size) { + xmlDocPtr doc; + xmlTextReaderPtr reader; + const char *docBuffer, *docUrl; + size_t docSize; + int opts; + + xmlFuzzDataInit(data, size); + opts = xmlFuzzReadInt(); + opts |= XML_PARSE_XINCLUDE; + + xmlFuzzReadEntities(); + docBuffer = xmlFuzzMainEntity(&docSize); + docUrl = xmlFuzzMainUrl(); + if (docBuffer == NULL) + goto exit; + + /* Pull parser */ + + doc = xmlReadMemory(docBuffer, docSize, docUrl, NULL, opts); + xmlXIncludeProcessFlags(doc, opts); + xmlFreeDoc(doc); + + /* Reader */ + + reader = xmlReaderForMemory(docBuffer, docSize, NULL, NULL, opts); + if (reader == NULL) + goto exit; + while (xmlTextReaderRead(reader) == 1) { + if (xmlTextReaderNodeType(reader) == XML_ELEMENT_NODE) { + int i, n = xmlTextReaderAttributeCount(reader); + for (i=0; i #include #include -#include #include #include "fuzz.h" @@ -49,8 +48,6 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { /* Pull parser */ doc = xmlReadMemory(docBuffer, docSize, docUrl, NULL, opts); - if (opts & XML_PARSE_XINCLUDE) - xmlXIncludeProcessFlags(doc, opts); /* Also test the serializer. */ xmlDocDumpMemory(doc, &out, &outSize); xmlFree(out); @@ -71,8 +68,6 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { } xmlParseChunk(ctxt, NULL, 0, 1); - if (opts & XML_PARSE_XINCLUDE) - xmlXIncludeProcessFlags(ctxt->myDoc, opts); xmlFreeDoc(ctxt->myDoc); xmlFreeParserCtxt(ctxt);