1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2024-10-26 12:25:09 +03:00

fuzz: Move to per-context resource loader

This commit is contained in:
Nick Wellnhofer 2024-06-11 15:48:32 +02:00
parent 89fcae4dfd
commit 116d8c0166
10 changed files with 93 additions and 32 deletions

View File

@ -964,7 +964,6 @@ LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
return 0;
}

View File

@ -386,6 +386,33 @@ xmlFuzzMainEntity(size_t *size) {
return(fuzzData.mainEntity->data);
}
/**
* xmlFuzzResourceLoader:
*
* The resource loader for fuzz data.
*/
int
xmlFuzzResourceLoader(void *data ATTRIBUTE_UNUSED, const char *URL,
const char *ID ATTRIBUTE_UNUSED,
int type ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED,
xmlParserInputPtr *out) {
xmlParserInputPtr input;
xmlFuzzEntityInfo *entity;
entity = xmlHashLookup(fuzzData.entities, (xmlChar *) URL);
if (entity == NULL)
return(XML_IO_ENOENT);
input = xmlInputCreateMemory(URL, entity->data, entity->size,
XML_INPUT_BUF_STATIC |
XML_INPUT_BUF_ZERO_TERMINATED);
if (input == NULL)
return(XML_ERR_NO_MEMORY);
*out = input;
return(XML_ERR_OK);
}
/**
* xmlFuzzEntityLoader:
*

View File

@ -104,6 +104,10 @@ xmlFuzzMainUrl(void);
const char *
xmlFuzzMainEntity(size_t *size);
int
xmlFuzzResourceLoader(void *data, const char *URL, const char *ID,
int type, int flags, xmlParserInputPtr *out);
xmlParserInputPtr
xmlFuzzEntityLoader(const char *URL, const char *ID, xmlParserCtxtPtr ctxt);

View File

@ -50,25 +50,30 @@ static struct {
#if defined(HAVE_SCHEMA_FUZZER) || \
defined(HAVE_XML_FUZZER)
/*
* A custom entity loader that writes all external DTDs or entities to a
* single file in the format expected by xmlFuzzEntityLoader.
* A custom resource loader that writes all external DTDs or entities to a
* single file in the format expected by xmlFuzzResourceLoader.
*/
static xmlParserInputPtr
fuzzEntityRecorder(const char *URL, const char *ID,
xmlParserCtxtPtr ctxt) {
static int
fuzzResourceRecorder(void *data ATTRIBUTE_UNUSED, const char *URL,
const char *ID ATTRIBUTE_UNUSED,
int type ATTRIBUTE_UNUSED, int flags,
xmlParserInputPtr *out) {
xmlParserInputPtr in;
static const int chunkSize = 16384;
int len;
int code, len;
in = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
if (in == NULL)
return(NULL);
*out = NULL;
code = xmlInputCreateUrl(URL, flags, &in);
if (code != XML_ERR_OK)
return(code);
if (globalData.entities == NULL) {
globalData.entities = xmlHashCreate(4);
} else if (xmlHashLookup(globalData.entities,
(const xmlChar *) URL) != NULL) {
return(in);
*out = in;
return(XML_ERR_OK);
}
do {
@ -76,7 +81,7 @@ fuzzEntityRecorder(const char *URL, const char *ID,
if (len < 0) {
fprintf(stderr, "Error reading %s\n", URL);
xmlFreeInputStream(in);
return(NULL);
return(in->buf->error);
}
} while (len > 0);
@ -89,7 +94,7 @@ fuzzEntityRecorder(const char *URL, const char *ID,
xmlHashAddEntry(globalData.entities, (const xmlChar *) URL,
globalData.entities);
return(xmlNoNetExternalEntityLoader(URL, ID, ctxt));
return(xmlInputCreateUrl(URL, flags, out));
}
static void
@ -97,12 +102,10 @@ fuzzRecorderInit(FILE *out) {
globalData.out = out;
globalData.entities = xmlHashCreate(8);
globalData.oldLoader = xmlGetExternalEntityLoader();
xmlSetExternalEntityLoader(fuzzEntityRecorder);
}
static void
fuzzRecorderCleanup(void) {
xmlSetExternalEntityLoader(globalData.oldLoader);
xmlHashFree(globalData.entities, NULL);
globalData.out = NULL;
globalData.entities = NULL;
@ -114,6 +117,7 @@ fuzzRecorderCleanup(void) {
static int
processXml(const char *docFile, FILE *out) {
int opts = XML_PARSE_NOENT | XML_PARSE_DTDLOAD;
xmlParserCtxtPtr ctxt;
xmlDocPtr doc;
if (globalData.flags & FLAG_LINT) {
@ -146,11 +150,21 @@ processXml(const char *docFile, FILE *out) {
fuzzRecorderInit(out);
doc = xmlReadFile(docFile, NULL, opts);
ctxt = xmlNewParserCtxt();
xmlCtxtSetResourceLoader(ctxt, fuzzResourceRecorder, NULL);
doc = xmlCtxtReadFile(ctxt, docFile, NULL, opts);
#ifdef LIBXML_XINCLUDE_ENABLED
xmlXIncludeProcessFlags(doc, opts);
{
xmlXIncludeCtxtPtr xinc = xmlXIncludeNewContext(doc);
xmlXIncludeSetResourceLoader(xinc, fuzzResourceRecorder, NULL);
xmlXIncludeSetFlags(xinc, opts);
xmlXIncludeProcessNode(xinc, (xmlNodePtr) doc);
xmlXIncludeFreeContext(xinc);
}
#endif
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctxt);
fuzzRecorderCleanup();
@ -200,6 +214,7 @@ processSchema(const char *docFile, FILE *out) {
pctxt = xmlSchemaNewParserCtxt(docFile);
xmlSchemaSetParserErrors(pctxt, xmlFuzzErrorFunc, xmlFuzzErrorFunc, NULL);
xmlSchemaSetResourceLoader(pctxt, fuzzResourceRecorder, NULL);
schema = xmlSchemaParse(pctxt);
xmlSchemaFreeParserCtxt(pctxt);
xmlSchemaFree(schema);

View File

@ -102,7 +102,6 @@ LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
return 0;
}
@ -137,6 +136,8 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
if (reader == NULL)
goto exit;
xmlTextReaderSetResourceLoader(reader, xmlFuzzResourceLoader, NULL);
i = 0;
while (i < programSize) {
int op = program[i++];

View File

@ -18,7 +18,6 @@ LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
return 0;
}
@ -39,6 +38,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlFuzzMemSetLimit(maxAlloc);
pctxt = xmlSchemaNewParserCtxt(xmlFuzzMainUrl());
xmlSchemaSetParserErrors(pctxt, xmlFuzzErrorFunc, xmlFuzzErrorFunc, NULL);
xmlSchemaSetResourceLoader(pctxt, xmlFuzzResourceLoader, NULL);
xmlSchemaFree(xmlSchemaParse(pctxt));
xmlSchemaFreeParserCtxt(pctxt);

View File

@ -148,6 +148,7 @@ error:
#ifdef HAVE_XML_FUZZER
static int
testEntityLoader(void) {
xmlParserCtxtPtr ctxt;
static const char data[] =
"doc.xml\\\n"
"<!DOCTYPE doc SYSTEM \"doc.dtd\">\n"
@ -162,13 +163,14 @@ testEntityLoader(void) {
xmlDocPtr doc;
int ret = 0;
xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
xmlFuzzDataInit(data, sizeof(data) - 1);
xmlFuzzReadEntities();
docBuffer = xmlFuzzMainEntity(&docSize);
doc = xmlReadMemory(docBuffer, docSize, NULL, NULL,
XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
ctxt = xmlNewParserCtxt();
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, NULL, NULL,
XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
xmlFreeParserCtxt(ctxt);
#ifdef LIBXML_OUTPUT_ENABLED
{

View File

@ -20,7 +20,6 @@ LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
return 0;
}
@ -51,6 +50,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlFuzzMemSetLimit(maxAlloc);
ctxt = xmlNewParserCtxt();
if (ctxt != NULL) {
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL, opts);
xmlFuzzCheckMallocFailure("xmlCtxtReadMemory",
ctxt->errNo == XML_ERR_NO_MEMORY);
@ -61,12 +61,21 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
/* Post validation */
xmlFuzzMemSetLimit(maxAlloc);
doc = xmlReadMemory(docBuffer, docSize, docUrl, NULL,
opts & ~XML_PARSE_DTDVALID);
vctxt = xmlNewValidCtxt();
xmlValidateDocument(vctxt, doc);
xmlFreeValidCtxt(vctxt);
xmlFreeDoc(doc);
ctxt = xmlNewParserCtxt();
if (ctxt != NULL) {
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL,
opts & ~XML_PARSE_DTDVALID);
xmlFreeParserCtxt(ctxt);
/* Post validation requires global callbacks */
xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
vctxt = xmlNewValidCtxt();
xmlValidateDocument(vctxt, doc);
xmlFreeValidCtxt(vctxt);
xmlFreeDoc(doc);
xmlSetExternalEntityLoader(NULL);
}
/* Push parser */
@ -78,6 +87,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlFuzzMemSetLimit(maxAlloc);
ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, docUrl);
if (ctxt != NULL) {
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
xmlCtxtUseOptions(ctxt, opts);
for (consumed = 0; consumed < docSize; consumed += chunkSize) {

View File

@ -21,7 +21,6 @@ LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
return 0;
}
@ -53,11 +52,14 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlXIncludeCtxtPtr xinc;
xmlDocPtr copy;
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL, opts);
xmlFuzzCheckMallocFailure("xmlCtxtReadMemory",
ctxt->errNo == XML_ERR_NO_MEMORY);
xinc = xmlXIncludeNewContext(doc);
xmlXIncludeSetResourceLoader(xinc, xmlFuzzResourceLoader, NULL);
xmlXIncludeSetFlags(xinc, opts);
xmlXIncludeProcessNode(xinc, (xmlNodePtr) doc);
if (doc != NULL) {

View File

@ -21,7 +21,6 @@ LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
return 0;
}
@ -55,6 +54,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlFuzzMemSetLimit(maxAlloc);
ctxt = xmlNewParserCtxt();
if (ctxt != NULL) {
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL, opts);
xmlFuzzCheckMallocFailure("xmlCtxtReadMemory",
doc == NULL &&
@ -94,6 +94,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlFuzzMemSetLimit(maxAlloc);
ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, docUrl);
if (ctxt != NULL) {
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
xmlCtxtUseOptions(ctxt, opts);
for (consumed = 0; consumed < docSize; consumed += chunkSize) {