mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-10-24 13:33:01 +03:00
fuzz: Add separate XInclude fuzzer
XIncludes involve XPath processing which can still lead to timeouts when fuzzing. This will probably take a while to fix. The rest of the XML parsing code should hopefully run without timeouts now. OSS-Fuzz only shows a single timeout test case, so separate the XInclude from the core XML fuzzer.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
AUTOMAKE_OPTIONS = -Wno-syntax
|
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
|
check_PROGRAMS = testFuzzer
|
||||||
EXTRA_DIST = html.dict regexp.dict schema.dict xml.dict xpath.dict \
|
EXTRA_DIST = html.dict regexp.dict schema.dict xml.dict xpath.dict \
|
||||||
static_seed/uri static_seed/regexp fuzz.h
|
static_seed/uri static_seed/regexp fuzz.h
|
||||||
@@ -19,8 +19,6 @@ XML_SEED_CORPUS_SRC = \
|
|||||||
'$(top_srcdir)/test/valid/*.xml' \
|
'$(top_srcdir)/test/valid/*.xml' \
|
||||||
'$(top_srcdir)/test/VC/*' \
|
'$(top_srcdir)/test/VC/*' \
|
||||||
'$(top_srcdir)/test/VCM/*' \
|
'$(top_srcdir)/test/VCM/*' \
|
||||||
'$(top_srcdir)/test/XInclude/docs/*' \
|
|
||||||
'$(top_srcdir)/test/XInclude/without-reader/*' \
|
|
||||||
'$(top_srcdir)/test/xmlid/*'
|
'$(top_srcdir)/test/xmlid/*'
|
||||||
|
|
||||||
testFuzzer_SOURCES = testFuzzer.c fuzz.c
|
testFuzzer_SOURCES = testFuzzer.c fuzz.c
|
||||||
@@ -28,7 +26,7 @@ testFuzzer_SOURCES = testFuzzer.c fuzz.c
|
|||||||
.PHONY: corpus clean-corpus
|
.PHONY: corpus clean-corpus
|
||||||
|
|
||||||
corpus: seed/html.stamp seed/regexp.stamp seed/schema.stamp seed/uri.stamp \
|
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
|
check-local: corpus
|
||||||
./testFuzzer$(EXEEXT)
|
./testFuzzer$(EXEEXT)
|
||||||
@@ -60,6 +58,26 @@ fuzz-xml: xml$(EXEEXT) seed/xml.stamp
|
|||||||
-timeout=20 \
|
-timeout=20 \
|
||||||
corpus/xml seed/xml
|
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
|
# HTML fuzzer
|
||||||
|
|
||||||
seed/html.stamp: genSeed$(EXEEXT)
|
seed/html.stamp: genSeed$(EXEEXT)
|
||||||
|
|||||||
@@ -27,9 +27,12 @@ extern "C" {
|
|||||||
#if 1
|
#if 1
|
||||||
#define HAVE_URI_FUZZER
|
#define HAVE_URI_FUZZER
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(LIBXML_XINCLUDE_ENABLED) && \
|
||||||
|
defined(LIBXML_READER_ENABLED)
|
||||||
|
#define HAVE_XINCLUDE_FUZZER
|
||||||
|
#endif
|
||||||
#if defined(LIBXML_OUTPUT_ENABLED) && \
|
#if defined(LIBXML_OUTPUT_ENABLED) && \
|
||||||
defined(LIBXML_READER_ENABLED) && \
|
defined(LIBXML_READER_ENABLED)
|
||||||
defined(LIBXML_XINCLUDE_ENABLED)
|
|
||||||
#define HAVE_XML_FUZZER
|
#define HAVE_XML_FUZZER
|
||||||
#endif
|
#endif
|
||||||
#if defined(LIBXML_XPATH_ENABLED)
|
#if defined(LIBXML_XPATH_ENABLED)
|
||||||
|
|||||||
@@ -406,6 +406,11 @@ main(int argc, const char **argv) {
|
|||||||
#ifdef HAVE_SCHEMA_FUZZER
|
#ifdef HAVE_SCHEMA_FUZZER
|
||||||
processArg = processPattern;
|
processArg = processPattern;
|
||||||
globalData.processFile = processSchema;
|
globalData.processFile = processSchema;
|
||||||
|
#endif
|
||||||
|
} else if (strcmp(fuzzer, "xinclude") == 0) {
|
||||||
|
#ifdef HAVE_XINCLUDE_FUZZER
|
||||||
|
processArg = processPattern;
|
||||||
|
globalData.processFile = processXml;
|
||||||
#endif
|
#endif
|
||||||
} else if (strcmp(fuzzer, "xml") == 0) {
|
} else if (strcmp(fuzzer, "xml") == 0) {
|
||||||
#ifdef HAVE_XML_FUZZER
|
#ifdef HAVE_XML_FUZZER
|
||||||
|
|||||||
@@ -52,6 +52,16 @@ int fuzzUri(const char *data, size_t size);
|
|||||||
#undef LLVMFuzzerTestOneInput
|
#undef LLVMFuzzerTestOneInput
|
||||||
#endif
|
#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
|
#ifdef HAVE_XML_FUZZER
|
||||||
int fuzzXmlInit(int *argc, char ***argv);
|
int fuzzXmlInit(int *argc, char ***argv);
|
||||||
int fuzzXml(const char *data, size_t size);
|
int fuzzXml(const char *data, size_t size);
|
||||||
@@ -183,6 +193,10 @@ main(void) {
|
|||||||
if (testFuzzer(NULL, fuzzUri, "seed/uri/*") != 0)
|
if (testFuzzer(NULL, fuzzUri, "seed/uri/*") != 0)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_XINCLUDE_FUZZER
|
||||||
|
if (testFuzzer(fuzzXIncludeInit, fuzzXInclude, "seed/xinclude/*") != 0)
|
||||||
|
ret = 1;
|
||||||
|
#endif
|
||||||
#ifdef HAVE_XML_FUZZER
|
#ifdef HAVE_XML_FUZZER
|
||||||
if (testFuzzer(fuzzXmlInit, fuzzXml, "seed/xml/*") != 0)
|
if (testFuzzer(fuzzXmlInit, fuzzXml, "seed/xml/*") != 0)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|||||||
73
fuzz/xinclude.c
Normal file
73
fuzz/xinclude.c
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* xinclude.c: a libFuzzer target to test the XInclude engine.
|
||||||
|
*
|
||||||
|
* See Copyright for the status of this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libxml/catalog.h>
|
||||||
|
#include <libxml/parser.h>
|
||||||
|
#include <libxml/tree.h>
|
||||||
|
#include <libxml/xmlerror.h>
|
||||||
|
#include <libxml/xinclude.h>
|
||||||
|
#include <libxml/xmlreader.h>
|
||||||
|
#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<n; i++) {
|
||||||
|
xmlTextReaderMoveToAttributeNo(reader, i);
|
||||||
|
while (xmlTextReaderReadAttributeValue(reader) == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xmlFreeTextReader(reader);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
xmlFuzzDataCleanup();
|
||||||
|
xmlResetLastError();
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
3
fuzz/xinclude.options
Normal file
3
fuzz/xinclude.options
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[libfuzzer]
|
||||||
|
dict = xml.dict
|
||||||
|
timeout = 20
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
#include <libxml/xmlerror.h>
|
#include <libxml/xmlerror.h>
|
||||||
#include <libxml/xinclude.h>
|
|
||||||
#include <libxml/xmlreader.h>
|
#include <libxml/xmlreader.h>
|
||||||
#include "fuzz.h"
|
#include "fuzz.h"
|
||||||
|
|
||||||
@@ -49,8 +48,6 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
|
|||||||
/* Pull parser */
|
/* Pull parser */
|
||||||
|
|
||||||
doc = xmlReadMemory(docBuffer, docSize, docUrl, NULL, opts);
|
doc = xmlReadMemory(docBuffer, docSize, docUrl, NULL, opts);
|
||||||
if (opts & XML_PARSE_XINCLUDE)
|
|
||||||
xmlXIncludeProcessFlags(doc, opts);
|
|
||||||
/* Also test the serializer. */
|
/* Also test the serializer. */
|
||||||
xmlDocDumpMemory(doc, &out, &outSize);
|
xmlDocDumpMemory(doc, &out, &outSize);
|
||||||
xmlFree(out);
|
xmlFree(out);
|
||||||
@@ -71,8 +68,6 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
xmlParseChunk(ctxt, NULL, 0, 1);
|
xmlParseChunk(ctxt, NULL, 0, 1);
|
||||||
if (opts & XML_PARSE_XINCLUDE)
|
|
||||||
xmlXIncludeProcessFlags(ctxt->myDoc, opts);
|
|
||||||
xmlFreeDoc(ctxt->myDoc);
|
xmlFreeDoc(ctxt->myDoc);
|
||||||
xmlFreeParserCtxt(ctxt);
|
xmlFreeParserCtxt(ctxt);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user