mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-10-26 00:37:43 +03:00
fuzz: Separate fuzzer for DTD validation
This commit is contained in:
1
fuzz/.gitignore
vendored
1
fuzz/.gitignore
vendored
@@ -6,6 +6,7 @@ schema
|
|||||||
seed/
|
seed/
|
||||||
testFuzzer
|
testFuzzer
|
||||||
uri
|
uri
|
||||||
|
valid
|
||||||
xinclude
|
xinclude
|
||||||
xml
|
xml
|
||||||
xpath
|
xpath
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
AUTOMAKE_OPTIONS = -Wno-syntax
|
AUTOMAKE_OPTIONS = -Wno-syntax
|
||||||
EXTRA_PROGRAMS = genSeed html regexp schema uri xinclude xml xpath
|
EXTRA_PROGRAMS = genSeed html regexp schema uri valid 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
|
||||||
@@ -27,7 +27,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/xinclude.stamp seed/xml.stamp seed/xpath.stamp
|
seed/valid.stamp seed/xinclude.stamp seed/xml.stamp seed/xpath.stamp
|
||||||
|
|
||||||
check-local: corpus
|
check-local: corpus
|
||||||
./testFuzzer$(EXEEXT)
|
./testFuzzer$(EXEEXT)
|
||||||
@@ -59,6 +59,24 @@ fuzz-xml: xml$(EXEEXT) seed/xml.stamp
|
|||||||
-timeout=20 \
|
-timeout=20 \
|
||||||
corpus/xml seed/xml
|
corpus/xml seed/xml
|
||||||
|
|
||||||
|
# DTD validation fuzzer
|
||||||
|
|
||||||
|
seed/valid.stamp: genSeed$(EXEEXT)
|
||||||
|
@mkdir -p seed/valid
|
||||||
|
./genSeed$(EXEEXT) valid $(XML_SEED_CORPUS_SRC)
|
||||||
|
@touch seed/valid.stamp
|
||||||
|
|
||||||
|
valid_SOURCES = valid.c fuzz.c
|
||||||
|
valid_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer
|
||||||
|
|
||||||
|
fuzz-valid: valid$(EXEEXT) seed/valid.stamp
|
||||||
|
@mkdir -p corpus/valid
|
||||||
|
./valid$(EXEEXT) \
|
||||||
|
-dict=xml.dict \
|
||||||
|
-max_len=$(XML_MAX_LEN) \
|
||||||
|
-timeout=20 \
|
||||||
|
corpus/valid seed/valid
|
||||||
|
|
||||||
# XInclude fuzzer
|
# XInclude fuzzer
|
||||||
|
|
||||||
seed/xinclude.stamp: genSeed$(EXEEXT)
|
seed/xinclude.stamp: genSeed$(EXEEXT)
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ extern "C" {
|
|||||||
#if 1
|
#if 1
|
||||||
#define HAVE_URI_FUZZER
|
#define HAVE_URI_FUZZER
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(LIBXML_VALID_ENABLED) && \
|
||||||
|
defined(LIBXML_READER_ENABLED)
|
||||||
|
#define HAVE_VALID_FUZZER
|
||||||
|
#endif
|
||||||
#if defined(LIBXML_XINCLUDE_ENABLED) && \
|
#if defined(LIBXML_XINCLUDE_ENABLED) && \
|
||||||
defined(LIBXML_READER_ENABLED)
|
defined(LIBXML_READER_ENABLED)
|
||||||
#define HAVE_XINCLUDE_FUZZER
|
#define HAVE_XINCLUDE_FUZZER
|
||||||
|
|||||||
@@ -418,6 +418,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, "valid") == 0) {
|
||||||
|
#ifdef HAVE_XINCLUDE_FUZZER
|
||||||
|
processArg = processPattern;
|
||||||
|
globalData.processFile = processXml;
|
||||||
#endif
|
#endif
|
||||||
} else if (strcmp(fuzzer, "xinclude") == 0) {
|
} else if (strcmp(fuzzer, "xinclude") == 0) {
|
||||||
#ifdef HAVE_XINCLUDE_FUZZER
|
#ifdef HAVE_XINCLUDE_FUZZER
|
||||||
|
|||||||
@@ -52,6 +52,16 @@ int fuzzUri(const char *data, size_t size);
|
|||||||
#undef LLVMFuzzerTestOneInput
|
#undef LLVMFuzzerTestOneInput
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_VALID_FUZZER
|
||||||
|
int fuzzValidInit(int *argc, char ***argv);
|
||||||
|
int fuzzValid(const char *data, size_t size);
|
||||||
|
#define LLVMFuzzerInitialize fuzzValidInit
|
||||||
|
#define LLVMFuzzerTestOneInput fuzzValid
|
||||||
|
#include "valid.c"
|
||||||
|
#undef LLVMFuzzerInitialize
|
||||||
|
#undef LLVMFuzzerTestOneInput
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_XINCLUDE_FUZZER
|
#ifdef HAVE_XINCLUDE_FUZZER
|
||||||
int fuzzXIncludeInit(int *argc, char ***argv);
|
int fuzzXIncludeInit(int *argc, char ***argv);
|
||||||
int fuzzXInclude(const char *data, size_t size);
|
int fuzzXInclude(const char *data, size_t size);
|
||||||
@@ -193,6 +203,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_VALID_FUZZER
|
||||||
|
if (testFuzzer(fuzzValidInit, fuzzValid, "seed/valid/*") != 0)
|
||||||
|
ret = 1;
|
||||||
|
#endif
|
||||||
#ifdef HAVE_XINCLUDE_FUZZER
|
#ifdef HAVE_XINCLUDE_FUZZER
|
||||||
if (testFuzzer(fuzzXIncludeInit, fuzzXInclude, "seed/xinclude/*") != 0)
|
if (testFuzzer(fuzzXIncludeInit, fuzzXInclude, "seed/xinclude/*") != 0)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|||||||
108
fuzz/valid.c
Normal file
108
fuzz/valid.c
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* valid.c: a libFuzzer target to test DTD validation.
|
||||||
|
*
|
||||||
|
* 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/xmlreader.h>
|
||||||
|
#include "fuzz.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
|
||||||
|
char ***argv ATTRIBUTE_UNUSED) {
|
||||||
|
xmlFuzzMemSetup();
|
||||||
|
xmlInitParser();
|
||||||
|
#ifdef LIBXML_CATALOG_ENABLED
|
||||||
|
xmlInitializeCatalog();
|
||||||
|
#endif
|
||||||
|
xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
|
||||||
|
xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LLVMFuzzerTestOneInput(const char *data, size_t size) {
|
||||||
|
static const size_t maxChunkSize = 128;
|
||||||
|
xmlDocPtr doc;
|
||||||
|
xmlParserCtxtPtr ctxt;
|
||||||
|
xmlValidCtxtPtr vctxt;
|
||||||
|
xmlTextReaderPtr reader;
|
||||||
|
const char *docBuffer, *docUrl;
|
||||||
|
size_t maxAlloc, docSize, consumed, chunkSize;
|
||||||
|
int opts;
|
||||||
|
|
||||||
|
xmlFuzzDataInit(data, size);
|
||||||
|
opts = (int) xmlFuzzReadInt(4);
|
||||||
|
opts &= ~XML_PARSE_XINCLUDE;
|
||||||
|
opts |= XML_PARSE_DTDVALID;
|
||||||
|
maxAlloc = xmlFuzzReadInt(4) % (size + 1);
|
||||||
|
|
||||||
|
xmlFuzzReadEntities();
|
||||||
|
docBuffer = xmlFuzzMainEntity(&docSize);
|
||||||
|
docUrl = xmlFuzzMainUrl();
|
||||||
|
if (docBuffer == NULL)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
/* Pull parser */
|
||||||
|
|
||||||
|
xmlFuzzMemSetLimit(maxAlloc);
|
||||||
|
doc = xmlReadMemory(docBuffer, docSize, docUrl, NULL, opts);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
|
/* Post validation */
|
||||||
|
|
||||||
|
xmlFuzzMemSetLimit(maxAlloc);
|
||||||
|
doc = xmlReadMemory(docBuffer, docSize, docUrl, NULL, opts & ~XML_PARSE_DTDVALID);
|
||||||
|
vctxt = xmlNewValidCtxt();
|
||||||
|
xmlValidateDocument(vctxt, doc);
|
||||||
|
xmlFreeValidCtxt(vctxt);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
|
/* Push parser */
|
||||||
|
|
||||||
|
xmlFuzzMemSetLimit(maxAlloc);
|
||||||
|
ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, docUrl);
|
||||||
|
if (ctxt == NULL)
|
||||||
|
goto exit;
|
||||||
|
xmlCtxtUseOptions(ctxt, opts);
|
||||||
|
|
||||||
|
for (consumed = 0; consumed < docSize; consumed += chunkSize) {
|
||||||
|
chunkSize = docSize - consumed;
|
||||||
|
if (chunkSize > maxChunkSize)
|
||||||
|
chunkSize = maxChunkSize;
|
||||||
|
xmlParseChunk(ctxt, docBuffer + consumed, chunkSize, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlParseChunk(ctxt, NULL, 0, 1);
|
||||||
|
xmlFreeDoc(ctxt->myDoc);
|
||||||
|
xmlFreeParserCtxt(ctxt);
|
||||||
|
|
||||||
|
/* Reader */
|
||||||
|
|
||||||
|
xmlFuzzMemSetLimit(maxAlloc);
|
||||||
|
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:
|
||||||
|
xmlFuzzMemSetLimit(0);
|
||||||
|
xmlFuzzDataCleanup();
|
||||||
|
xmlResetLastError();
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -36,6 +36,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
|
|||||||
|
|
||||||
xmlFuzzDataInit(data, size);
|
xmlFuzzDataInit(data, size);
|
||||||
opts = (int) xmlFuzzReadInt(4);
|
opts = (int) xmlFuzzReadInt(4);
|
||||||
|
opts &= ~XML_PARSE_DTDVALID;
|
||||||
opts |= XML_PARSE_XINCLUDE;
|
opts |= XML_PARSE_XINCLUDE;
|
||||||
maxAlloc = xmlFuzzReadInt(4) % (size + 1);
|
maxAlloc = xmlFuzzReadInt(4) % (size + 1);
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
|
|||||||
|
|
||||||
xmlFuzzDataInit(data, size);
|
xmlFuzzDataInit(data, size);
|
||||||
opts = (int) xmlFuzzReadInt(4);
|
opts = (int) xmlFuzzReadInt(4);
|
||||||
opts &= ~XML_PARSE_XINCLUDE;
|
opts &= ~XML_PARSE_XINCLUDE & ~XML_PARSE_DTDVALID;
|
||||||
maxAlloc = xmlFuzzReadInt(4) % (size + 1);
|
maxAlloc = xmlFuzzReadInt(4) % (size + 1);
|
||||||
|
|
||||||
xmlFuzzReadEntities();
|
xmlFuzzReadEntities();
|
||||||
|
|||||||
Reference in New Issue
Block a user