1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2024-12-23 17:33:50 +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:
Nick Wellnhofer 2022-12-26 17:49:27 +01:00
parent 66e9fd66e8
commit 09dac45ab9
7 changed files with 122 additions and 11 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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;

73
fuzz/xinclude.c Normal file
View 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
View File

@ -0,0 +1,3 @@
[libfuzzer]
dict = xml.dict
timeout = 20

View File

@ -8,7 +8,6 @@
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlerror.h>
#include <libxml/xinclude.h>
#include <libxml/xmlreader.h>
#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);