diff --git a/fuzz/api.c b/fuzz/api.c index 49bebcb1..288dfbac 100644 --- a/fuzz/api.c +++ b/fuzz/api.c @@ -970,7 +970,7 @@ LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED, int LLVMFuzzerTestOneInput(const char *data, size_t size) { - size_t maxAlloc; + size_t failurePos; int i; if (size > 1000) @@ -980,8 +980,8 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlFuzzDataInit(data, size); - maxAlloc = xmlFuzzReadInt(4) % (size * 50 + 10); - xmlFuzzMemSetLimit(maxAlloc); + failurePos = xmlFuzzReadInt(4) % (size * 50 + 10); + xmlFuzzInjectFailure(failurePos); /* * Interpreter loop @@ -1804,7 +1804,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { node, BAD_CAST "lang", XML_XML_NAMESPACE); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); removeChildren((xmlNodePtr) attr, 0); res = xmlNodeSetLang( node, @@ -1838,7 +1838,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { node, BAD_CAST "space", XML_XML_NAMESPACE); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); removeChildren((xmlNodePtr) attr, 0); res = xmlNodeSetSpacePreserve( node, @@ -1890,7 +1890,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { node, BAD_CAST "base", XML_XML_NAMESPACE); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); removeChildren((xmlNodePtr) attr, 0); res = xmlNodeSetBase( node, @@ -2029,7 +2029,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { oldAttr = xmlHasNsProp(node, name, NULL); else oldAttr = xmlHasNsProp(node, localName, ns->href); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); if (oldAttr != NULL) removeChildren((xmlNodePtr) oldAttr, 0); @@ -2056,7 +2056,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { name = getStr(0); value = getStr(1); oldAttr = xmlHasNsProp(node, name, ns ? ns->href : NULL); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); if (oldAttr != NULL) removeChildren((xmlNodePtr) oldAttr, 0); attr = xmlSetNsProp(node, ns, name, value); @@ -2105,7 +2105,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { node = getNode(0); name = getStr(0); attr = xmlHasNsProp(node, name, NULL); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); if (attr != NULL) removeChildren((xmlNodePtr) attr, 1); setInt(0, xmlUnsetProp(node, name)); @@ -2127,7 +2127,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { ns = nodeGetNs(getNode(1), getInt(1)); name = getStr(0); attr = xmlHasNsProp(node, name, ns ? ns->href : NULL); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); if (attr != NULL) removeChildren((xmlNodePtr) attr, 1); setInt(0, xmlUnsetNsProp(node, ns, name)); @@ -2389,7 +2389,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlAttrPtr attr = xmlHasNsProp(parent, node->name, node->ns ? node->ns->href : NULL); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); /* Attribute might be replaced */ if (attr != NULL && attr != (xmlAttrPtr) node) removeChildren((xmlNodePtr) attr, 1); @@ -3016,7 +3016,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { node = getNode(0); type = node ? node->type : 0; xmlValidCtxtPtr vctxt = xmlNewValidCtxt(); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); switch (type) { case XML_DOCUMENT_NODE: @@ -3178,7 +3178,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { incStrIdx(); buffer = xmlBufferCreate(); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); node = getNode(0); doc = node ? node->doc : NULL; level = getInt(0); @@ -3302,7 +3302,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { incStrIdx(); output = xmlAllocOutputBuffer(NULL); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); node = getNode(0); doc = node ? node->doc : NULL; encoding = (const char *) getStr(1); @@ -3570,7 +3570,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { break; } - xmlFuzzCheckMallocFailure(vars->opName, oomReport); + xmlFuzzCheckFailureReport(vars->opName, oomReport, 0); } for (i = 0; i < REG_MAX; i++) @@ -3583,7 +3583,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { dropNode(node); } - xmlFuzzMemSetLimit(0); + xmlFuzzInjectFailure(0); xmlFuzzDataCleanup(); xmlResetLastError(); return(0); diff --git a/fuzz/fuzz.c b/fuzz/fuzz.c index 03585414..aec664cb 100644 --- a/fuzz/fuzz.c +++ b/fuzz/fuzz.c @@ -42,9 +42,10 @@ static struct { xmlFuzzEntityInfo *mainEntity; } fuzzData; -size_t fuzzNumAllocs; -size_t fuzzMaxAllocs; +size_t fuzzNumAttempts; +size_t fuzzFailurePos; int fuzzAllocFailed; +int fuzzIoFailed; /** * xmlFuzzErrorFunc: @@ -67,29 +68,61 @@ xmlFuzzSErrorFunc(void *ctx ATTRIBUTE_UNUSED, } /* - * Malloc failure injection. + * Failure injection. * - * To debug issues involving malloc failures, it's often helpful to set - * MALLOC_ABORT to 1. This should provide a backtrace of the failed - * allocation. + * To debug issues involving injected failures, it's often helpful to set + * FAILURE_ABORT to 1. This should provide a backtrace of the failed + * operation. */ -#define XML_FUZZ_MALLOC_ABORT 0 +#define XML_FUZZ_FAILURE_ABORT 0 + +void +xmlFuzzInjectFailure(size_t failurePos) { + fuzzNumAttempts = 0; + fuzzFailurePos = failurePos; + fuzzAllocFailed = 0; + fuzzIoFailed = 0; +} + +static int +xmlFuzzTryMalloc(void) { + if (fuzzFailurePos > 0) { + fuzzNumAttempts += 1; + if (fuzzNumAttempts == fuzzFailurePos) { +#if XML_FUZZ_FAILURE_ABORT + abort(); +#endif + fuzzAllocFailed = 1; + return -1; + } + } + + return 0; +} + +static int +xmlFuzzTryIo(void) { + if (fuzzFailurePos > 0) { + fuzzNumAttempts += 1; + if (fuzzNumAttempts == fuzzFailurePos) { +#if XML_FUZZ_FAILURE_ABORT + abort(); +#endif + fuzzIoFailed = 1; + return -1; + } + } + + return 0; +} static void * xmlFuzzMalloc(size_t size) { void *ret; - if (fuzzMaxAllocs > 0) { - fuzzNumAllocs += 1; - if (fuzzNumAllocs == fuzzMaxAllocs) { -#if XML_FUZZ_MALLOC_ABORT - abort(); -#endif - fuzzAllocFailed = 1; - return NULL; - } - } + if (xmlFuzzTryMalloc() < 0) + return NULL; ret = malloc(size); if (ret == NULL) @@ -102,16 +135,8 @@ static void * xmlFuzzRealloc(void *ptr, size_t size) { void *ret; - if (fuzzMaxAllocs > 0) { - fuzzNumAllocs += 1; - if (fuzzNumAllocs == fuzzMaxAllocs) { -#if XML_FUZZ_MALLOC_ABORT - abort(); -#endif - fuzzAllocFailed = 1; - return NULL; - } - } + if (xmlFuzzTryMalloc() < 0) + return NULL; ret = realloc(ptr, size); if (ret == NULL) @@ -125,31 +150,31 @@ xmlFuzzMemSetup(void) { xmlMemSetup(free, xmlFuzzMalloc, xmlFuzzRealloc, xmlMemStrdup); } -void -xmlFuzzMemSetLimit(size_t limit) { - fuzzNumAllocs = 0; - fuzzMaxAllocs = limit; - fuzzAllocFailed = 0; -} - int xmlFuzzMallocFailed(void) { return fuzzAllocFailed; } void -xmlFuzzResetMallocFailed(void) { +xmlFuzzResetFailure(void) { fuzzAllocFailed = 0; + fuzzIoFailed = 0; } void -xmlFuzzCheckMallocFailure(const char *func, int error) { - if (error >= 0 && fuzzAllocFailed != error) { +xmlFuzzCheckFailureReport(const char *func, int oomReport, int ioReport) { + if (oomReport >= 0 && fuzzAllocFailed != oomReport) { fprintf(stderr, "%s: malloc failure %s reported\n", func, fuzzAllocFailed ? "not" : "erroneously"); abort(); } + if (ioReport >= 0 && fuzzIoFailed != ioReport) { + fprintf(stderr, "%s: IO failure %s reported\n", + func, fuzzIoFailed ? "not" : "erroneously"); + abort(); + } fuzzAllocFailed = 0; + fuzzIoFailed = 0; } /** @@ -413,6 +438,10 @@ xmlFuzzResourceLoader(void *data ATTRIBUTE_UNUSED, const char *URL, if (entity == NULL) return(XML_IO_ENOENT); + /* IO failure injection */ + if (xmlFuzzTryIo() < 0) + return(XML_IO_EIO); + input = xmlNewInputFromMemory(URL, entity->data, entity->size, XML_INPUT_BUF_STATIC | XML_INPUT_BUF_ZERO_TERMINATED); diff --git a/fuzz/fuzz.h b/fuzz/fuzz.h index 189aa08f..f5634ac4 100644 --- a/fuzz/fuzz.h +++ b/fuzz/fuzz.h @@ -68,16 +68,16 @@ void xmlFuzzMemSetup(void); void -xmlFuzzMemSetLimit(size_t limit); +xmlFuzzInjectFailure(size_t failurePos); int xmlFuzzMallocFailed(void); void -xmlFuzzResetMallocFailed(void); +xmlFuzzResetFailure(void); void -xmlFuzzCheckMallocFailure(const char *func, int expect); +xmlFuzzCheckFailureReport(const char *func, int oomReport, int ioReport); void xmlFuzzDataInit(const char *data, size_t size); diff --git a/fuzz/html.c b/fuzz/html.c index 36913121..aea05320 100644 --- a/fuzz/html.c +++ b/fuzz/html.c @@ -27,12 +27,12 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlParserCtxtPtr ctxt; htmlDocPtr doc; const char *docBuffer; - size_t maxAlloc, docSize; + size_t failurePos, docSize; int opts; xmlFuzzDataInit(data, size); opts = (int) xmlFuzzReadInt(4); - maxAlloc = xmlFuzzReadInt(4) % (size + 100); + failurePos = xmlFuzzReadInt(4) % (size + 100); docBuffer = xmlFuzzReadRemaining(&docSize); if (docBuffer == NULL) { @@ -42,13 +42,14 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { /* Pull parser */ - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); ctxt = htmlNewParserCtxt(); if (ctxt != NULL) { xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL); doc = htmlCtxtReadMemory(ctxt, docBuffer, docSize, NULL, NULL, opts); - xmlFuzzCheckMallocFailure("htmlCtxtReadMemory", - ctxt->errNo == XML_ERR_NO_MEMORY); + xmlFuzzCheckFailureReport("htmlCtxtReadMemory", + ctxt->errNo == XML_ERR_NO_MEMORY, + ctxt->errNo == XML_IO_EIO); if (doc != NULL) { xmlDocPtr copy; @@ -66,12 +67,12 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { htmlDocContentDumpOutput(out, doc, NULL); content = xmlOutputBufferGetContent(out); xmlOutputBufferClose(out); - xmlFuzzCheckMallocFailure("htmlDocContentDumpOutput", - content == NULL); + xmlFuzzCheckFailureReport("htmlDocContentDumpOutput", + content == NULL, 0); #endif copy = xmlCopyDoc(doc, 1); - xmlFuzzCheckMallocFailure("xmlCopyNode", copy == NULL); + xmlFuzzCheckFailureReport("xmlCopyNode", copy == NULL, 0); xmlFreeDoc(copy); xmlFreeDoc(doc); @@ -88,7 +89,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { static const size_t maxChunkSize = 128; size_t consumed, chunkSize; - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); ctxt = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL, XML_CHAR_ENCODING_NONE); @@ -104,8 +105,9 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { } htmlParseChunk(ctxt, NULL, 0, 1); - xmlFuzzCheckMallocFailure("htmlParseChunk", - ctxt->errNo == XML_ERR_NO_MEMORY); + xmlFuzzCheckFailureReport("htmlParseChunk", + ctxt->errNo == XML_ERR_NO_MEMORY, + ctxt->errNo == XML_IO_EIO); xmlFreeDoc(ctxt->myDoc); htmlFreeParserCtxt(ctxt); } @@ -114,7 +116,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { /* Cleanup */ - xmlFuzzMemSetLimit(0); + xmlFuzzInjectFailure(0); xmlFuzzDataCleanup(); xmlResetLastError(); diff --git a/fuzz/reader.c b/fuzz/reader.c index 83d6567e..9c086d92 100644 --- a/fuzz/reader.c +++ b/fuzz/reader.c @@ -107,14 +107,14 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { const xmlError *error; const char *docBuffer; const unsigned char *program; - size_t maxAlloc, docSize, programSize, i; + size_t failurePos, docSize, programSize, i; size_t totalStringSize = 0; int opts; int oomReport = 0; xmlFuzzDataInit(data, size); opts = (int) xmlFuzzReadInt(4); - maxAlloc = xmlFuzzReadInt(4) % (size + 100); + failurePos = xmlFuzzReadInt(4) % (size + 100); program = (const unsigned char *) xmlFuzzReadString(&programSize); if (programSize > 1000) @@ -138,7 +138,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { fprintf(stderr, "\nEOF\n"); #endif - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); reader = xmlReaderForMemory(docBuffer, docSize, NULL, NULL, opts); if (reader == NULL) goto exit; @@ -539,7 +539,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { error = xmlTextReaderGetLastError(reader); if (error->code == XML_ERR_NO_MEMORY) oomReport = 1; - xmlFuzzCheckMallocFailure("reader", oomReport); + xmlFuzzCheckFailureReport("reader", oomReport, 0); xmlFreeTextReader(reader); @@ -547,7 +547,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlFreeDoc(doc); exit: - xmlFuzzMemSetLimit(0); + xmlFuzzInjectFailure(0); xmlFuzzDataCleanup(); xmlResetLastError(); return(0); diff --git a/fuzz/regexp.c b/fuzz/regexp.c index 919ce1dd..ca27af61 100644 --- a/fuzz/regexp.c +++ b/fuzz/regexp.c @@ -20,17 +20,17 @@ LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED, int LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlRegexpPtr regexp; - size_t maxAlloc; + size_t failurePos; const char *str1; if (size > 200) return(0); xmlFuzzDataInit(data, size); - maxAlloc = xmlFuzzReadInt(4) % (size * 8 + 100); + failurePos = xmlFuzzReadInt(4) % (size * 8 + 100); str1 = xmlFuzzReadString(NULL); - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); regexp = xmlRegexpCompile(BAD_CAST str1); if (xmlFuzzMallocFailed() && regexp != NULL) { fprintf(stderr, "malloc failure not reported\n"); @@ -42,7 +42,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { #endif xmlRegFreeRegexp(regexp); - xmlFuzzMemSetLimit(0); + xmlFuzzInjectFailure(0); xmlFuzzDataCleanup(); xmlResetLastError(); diff --git a/fuzz/schema.c b/fuzz/schema.c index fb1027ca..a6759a6d 100644 --- a/fuzz/schema.c +++ b/fuzz/schema.c @@ -24,24 +24,24 @@ LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED, int LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlSchemaParserCtxtPtr pctxt; - size_t maxAlloc; + size_t failurePos; if (size > 50000) return(0); - maxAlloc = xmlFuzzReadInt(4) % (size + 100); + failurePos = xmlFuzzReadInt(4) % (size + 100); xmlFuzzDataInit(data, size); xmlFuzzReadEntities(); - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); pctxt = xmlSchemaNewParserCtxt(xmlFuzzMainUrl()); xmlSchemaSetParserStructuredErrors(pctxt, xmlFuzzSErrorFunc, NULL); xmlSchemaSetResourceLoader(pctxt, xmlFuzzResourceLoader, NULL); xmlSchemaFree(xmlSchemaParse(pctxt)); xmlSchemaFreeParserCtxt(pctxt); - xmlFuzzMemSetLimit(0); + xmlFuzzInjectFailure(0); xmlFuzzDataCleanup(); xmlResetLastError(); diff --git a/fuzz/uri.c b/fuzz/uri.c index 72c6a293..03fcb24d 100644 --- a/fuzz/uri.c +++ b/fuzz/uri.c @@ -18,7 +18,7 @@ LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED, int LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlURIPtr uri; - size_t maxAlloc; + size_t failurePos; const char *str1, *str2; char *copy; xmlChar *strRes; @@ -28,20 +28,20 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { return(0); xmlFuzzDataInit(data, size); - maxAlloc = xmlFuzzReadInt(4) % (size * 8 + 100); + failurePos = xmlFuzzReadInt(4) % (size * 8 + 100); str1 = xmlFuzzReadString(NULL); str2 = xmlFuzzReadString(NULL); - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); intRes = xmlParseURISafe(str1, &uri); - xmlFuzzCheckMallocFailure("xmlParseURISafe", intRes == -1); + xmlFuzzCheckFailureReport("xmlParseURISafe", intRes == -1, 0); if (uri != NULL) { - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); strRes = xmlSaveUri(uri); - xmlFuzzCheckMallocFailure("xmlSaveURI", strRes == NULL); + xmlFuzzCheckFailureReport("xmlSaveURI", strRes == NULL, 0); xmlFree(strRes); xmlFreeURI(uri); } @@ -52,50 +52,51 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlFree(xmlSaveUri(uri)); xmlFreeURI(uri); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); strRes = BAD_CAST xmlURIUnescapeString(str1, -1, NULL); - xmlFuzzCheckMallocFailure("xmlURIUnescapeString", - str1 != NULL && strRes == NULL); + xmlFuzzCheckFailureReport("xmlURIUnescapeString", + str1 != NULL && strRes == NULL, 0); xmlFree(strRes); xmlFree(xmlURIEscape(BAD_CAST str1)); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); strRes = xmlCanonicPath(BAD_CAST str1); - xmlFuzzCheckMallocFailure("xmlCanonicPath", - str1 != NULL && strRes == NULL); + xmlFuzzCheckFailureReport("xmlCanonicPath", + str1 != NULL && strRes == NULL, 0); xmlFree(strRes); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); strRes = xmlPathToURI(BAD_CAST str1); - xmlFuzzCheckMallocFailure("xmlPathToURI", str1 != NULL && strRes == NULL); + xmlFuzzCheckFailureReport("xmlPathToURI", + str1 != NULL && strRes == NULL, 0); xmlFree(strRes); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); intRes = xmlBuildURISafe(BAD_CAST str2, BAD_CAST str1, &strRes); - xmlFuzzCheckMallocFailure("xmlBuildURISafe", intRes == -1); + xmlFuzzCheckFailureReport("xmlBuildURISafe", intRes == -1, 0); xmlFree(strRes); xmlFree(xmlBuildURI(BAD_CAST str2, BAD_CAST str1)); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); intRes = xmlBuildRelativeURISafe(BAD_CAST str2, BAD_CAST str1, &strRes); - xmlFuzzCheckMallocFailure("xmlBuildRelativeURISafe", intRes == -1); + xmlFuzzCheckFailureReport("xmlBuildRelativeURISafe", intRes == -1, 0); xmlFree(strRes); xmlFree(xmlBuildRelativeURI(BAD_CAST str2, BAD_CAST str1)); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); strRes = xmlURIEscapeStr(BAD_CAST str1, BAD_CAST str2); - xmlFuzzCheckMallocFailure("xmlURIEscapeStr", - str1 != NULL && strRes == NULL); + xmlFuzzCheckFailureReport("xmlURIEscapeStr", + str1 != NULL && strRes == NULL, 0); xmlFree(strRes); copy = (char *) xmlCharStrdup(str1); xmlNormalizeURIPath(copy); xmlFree(copy); - xmlFuzzMemSetLimit(0); + xmlFuzzInjectFailure(0); xmlFuzzDataCleanup(); return 0; diff --git a/fuzz/valid.c b/fuzz/valid.c index 0a1b332e..cab7cedc 100644 --- a/fuzz/valid.c +++ b/fuzz/valid.c @@ -28,14 +28,14 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlParserCtxtPtr ctxt; xmlDocPtr doc; const char *docBuffer, *docUrl; - size_t maxAlloc, docSize; + size_t failurePos, docSize; int opts; xmlFuzzDataInit(data, size); opts = (int) xmlFuzzReadInt(4); opts &= ~XML_PARSE_XINCLUDE; opts |= XML_PARSE_DTDVALID; - maxAlloc = xmlFuzzReadInt(4) % (size + 100); + failurePos = xmlFuzzReadInt(4) % (size + 100); xmlFuzzReadEntities(); docBuffer = xmlFuzzMainEntity(&docSize); @@ -45,33 +45,37 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { /* Pull parser */ - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); ctxt = xmlNewParserCtxt(); if (ctxt != NULL) { xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL); xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL); doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL, opts); - xmlFuzzCheckMallocFailure("xmlCtxtReadMemory", - ctxt->errNo == XML_ERR_NO_MEMORY); + xmlFuzzCheckFailureReport("xmlCtxtReadMemory", + ctxt->errNo == XML_ERR_NO_MEMORY, + ctxt->errNo == XML_IO_EIO); xmlFreeDoc(doc); xmlFreeParserCtxt(ctxt); } /* Post validation */ - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); ctxt = xmlNewParserCtxt(); if (ctxt != NULL) { xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL); xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL); doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL, opts & ~XML_PARSE_DTDVALID); - xmlFuzzCheckMallocFailure("xmlCtxtReadMemory", - ctxt->errNo == XML_ERR_NO_MEMORY); + xmlFuzzCheckFailureReport("xmlCtxtReadMemory", + doc == NULL && ctxt->errNo == XML_ERR_NO_MEMORY, + doc == NULL && ctxt->errNo == XML_IO_EIO); if (doc != NULL) { - xmlCtxtValidateDocument(ctxt, doc); - xmlFuzzCheckMallocFailure("xmlCtxtValidateDocument", - ctxt->errNo == XML_ERR_NO_MEMORY); + int valid = xmlCtxtValidateDocument(ctxt, doc); + + xmlFuzzCheckFailureReport("xmlCtxtValidateDocument", + !valid && ctxt->errNo == XML_ERR_NO_MEMORY, + !valid && ctxt->errNo == XML_IO_EIO); } xmlFreeDoc(doc); xmlFreeParserCtxt(ctxt); @@ -84,7 +88,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { static const size_t maxChunkSize = 128; size_t consumed, chunkSize; - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); /* * FIXME: xmlCreatePushParserCtxt can still report OOM errors * to stderr. @@ -105,8 +109,9 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { } xmlParseChunk(ctxt, NULL, 0, 1); - xmlFuzzCheckMallocFailure("xmlParseChunk", - ctxt->errNo == XML_ERR_NO_MEMORY); + xmlFuzzCheckFailureReport("xmlParseChunk", + ctxt->errNo == XML_ERR_NO_MEMORY, + ctxt->errNo == XML_IO_EIO); xmlFreeDoc(ctxt->myDoc); xmlFreeParserCtxt(ctxt); } @@ -114,7 +119,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { #endif exit: - xmlFuzzMemSetLimit(0); + xmlFuzzInjectFailure(0); xmlFuzzDataCleanup(); xmlResetLastError(); return(0); diff --git a/fuzz/xinclude.c b/fuzz/xinclude.c index b9c44e59..7bcb2189 100644 --- a/fuzz/xinclude.c +++ b/fuzz/xinclude.c @@ -30,13 +30,13 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlParserCtxtPtr ctxt; xmlDocPtr doc; const char *docBuffer, *docUrl; - size_t maxAlloc, docSize; + size_t failurePos, docSize; int opts; xmlFuzzDataInit(data, size); opts = (int) xmlFuzzReadInt(4); opts |= XML_PARSE_XINCLUDE; - maxAlloc = xmlFuzzReadInt(4) % (size + 100); + failurePos = xmlFuzzReadInt(4) % (size + 100); xmlFuzzReadEntities(); docBuffer = xmlFuzzMainEntity(&docSize); @@ -46,7 +46,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { /* Pull parser */ - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); ctxt = xmlNewParserCtxt(); if (ctxt != NULL) { xmlXIncludeCtxtPtr xinc; @@ -55,24 +55,27 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL); doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL, opts); - xmlFuzzCheckMallocFailure("xmlCtxtReadMemory", - ctxt->errNo == XML_ERR_NO_MEMORY); + xmlFuzzCheckFailureReport("xmlCtxtReadMemory", + doc == NULL && ctxt->errNo == XML_ERR_NO_MEMORY, + doc == NULL && ctxt->errNo == XML_IO_EIO); xinc = xmlXIncludeNewContext(doc); xmlXIncludeSetResourceLoader(xinc, xmlFuzzResourceLoader, NULL); xmlXIncludeSetFlags(xinc, opts); xmlXIncludeProcessNode(xinc, (xmlNodePtr) doc); if (doc != NULL) { - xmlFuzzCheckMallocFailure("xmlXIncludeProcessNode", + xmlFuzzCheckFailureReport("xmlXIncludeProcessNode", xinc == NULL || - xmlXIncludeGetLastError(xinc) == XML_ERR_NO_MEMORY); + xmlXIncludeGetLastError(xinc) == XML_ERR_NO_MEMORY, + xinc != NULL && + xmlXIncludeGetLastError(xinc) == XML_IO_EIO); } xmlXIncludeFreeContext(xinc); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); copy = xmlCopyDoc(doc, 1); if (doc != NULL) - xmlFuzzCheckMallocFailure("xmlCopyNode", copy == NULL); + xmlFuzzCheckFailureReport("xmlCopyNode", copy == NULL, 0); xmlFreeDoc(copy); xmlFreeDoc(doc); @@ -80,7 +83,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { } exit: - xmlFuzzMemSetLimit(0); + xmlFuzzInjectFailure(0); xmlFuzzDataCleanup(); xmlResetLastError(); return(0); diff --git a/fuzz/xml.c b/fuzz/xml.c index 1fb1f9f5..14df19c3 100644 --- a/fuzz/xml.c +++ b/fuzz/xml.c @@ -29,7 +29,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlParserCtxtPtr ctxt; xmlDocPtr doc; const char *docBuffer, *docUrl; - size_t maxAlloc, docSize; + size_t failurePos, docSize; int opts; xmlFuzzDataInit(data, size); @@ -40,7 +40,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { opts &= ~XML_PARSE_XINCLUDE & ~XML_PARSE_DTDVALID & ~XML_PARSE_SAX1; - maxAlloc = xmlFuzzReadInt(4) % (size + 100); + failurePos = xmlFuzzReadInt(4) % (size + 100); xmlFuzzReadEntities(); docBuffer = xmlFuzzMainEntity(&docSize); @@ -50,15 +50,15 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { /* Pull parser */ - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); ctxt = xmlNewParserCtxt(); if (ctxt != NULL) { xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL); xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL); doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL, opts); - xmlFuzzCheckMallocFailure("xmlCtxtReadMemory", - doc == NULL && - ctxt->errNo == XML_ERR_NO_MEMORY); + xmlFuzzCheckFailureReport("xmlCtxtReadMemory", + doc == NULL && ctxt->errNo == XML_ERR_NO_MEMORY, + doc == NULL && ctxt->errNo == XML_IO_EIO); if (doc != NULL) { #ifdef LIBXML_OUTPUT_ENABLED @@ -73,8 +73,9 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlSaveDoc(save, doc); errNo = xmlSaveFinish(save); - xmlFuzzCheckMallocFailure("xmlSaveDoc", - errNo == XML_ERR_NO_MEMORY); + xmlFuzzCheckFailureReport("xmlSaveDoc", + errNo == XML_ERR_NO_MEMORY, + errNo == XML_IO_EIO); } xmlBufferFree(buffer); #endif @@ -91,7 +92,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { static const size_t maxChunkSize = 128; size_t consumed, chunkSize; - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, docUrl); if (ctxt != NULL) { xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL); @@ -106,8 +107,9 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { } xmlParseChunk(ctxt, NULL, 0, 1); - xmlFuzzCheckMallocFailure("xmlParseChunk", - ctxt->errNo == XML_ERR_NO_MEMORY); + xmlFuzzCheckFailureReport("xmlParseChunk", + ctxt->errNo == XML_ERR_NO_MEMORY, + ctxt->errNo == XML_IO_EIO); xmlFreeDoc(ctxt->myDoc); xmlFreeParserCtxt(ctxt); } @@ -115,7 +117,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { #endif exit: - xmlFuzzMemSetLimit(0); + xmlFuzzInjectFailure(0); xmlFuzzDataCleanup(); xmlResetLastError(); return(0); diff --git a/fuzz/xpath.c b/fuzz/xpath.c index 2c25acb7..c7d05b43 100644 --- a/fuzz/xpath.c +++ b/fuzz/xpath.c @@ -27,14 +27,14 @@ int LLVMFuzzerTestOneInput(const char *data, size_t size) { xmlDocPtr doc; const char *expr, *xml; - size_t maxAlloc, exprSize, xmlSize; + size_t failurePos, exprSize, xmlSize; if (size > 10000) return(0); xmlFuzzDataInit(data, size); - maxAlloc = xmlFuzzReadInt(4) % (size + 100); + failurePos = xmlFuzzReadInt(4) % (size + 100); expr = xmlFuzzReadString(&exprSize); xml = xmlFuzzReadString(&xmlSize); @@ -43,7 +43,7 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { if (doc != NULL) { xmlXPathContextPtr xpctxt; - xmlFuzzMemSetLimit(maxAlloc); + xmlFuzzInjectFailure(failurePos); xpctxt = xmlXPathNewContext(doc); if (xpctxt != NULL) { @@ -53,17 +53,16 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) { xpctxt->opLimit = 500000; res = xmlXPathContextSetCache(xpctxt, 1, 4, 0); - xmlFuzzCheckMallocFailure("xmlXPathContextSetCache", res == -1); + xmlFuzzCheckFailureReport("xmlXPathContextSetCache", res == -1, 0); - xmlFuzzResetMallocFailed(); + xmlFuzzResetFailure(); xmlXPathFreeObject(xmlXPtrEval(BAD_CAST expr, xpctxt)); - xmlFuzzCheckMallocFailure("xmlXPtrEval", - xpctxt->lastError.code == - XML_ERR_NO_MEMORY); + xmlFuzzCheckFailureReport("xmlXPtrEval", + xpctxt->lastError.code == XML_ERR_NO_MEMORY, 0); xmlXPathFreeContext(xpctxt); } - xmlFuzzMemSetLimit(0); + xmlFuzzInjectFailure(0); xmlFreeDoc(doc); }