| /* |
| * testFuzzer.c: Test program for the custom entity loader used to fuzz |
| * with multiple inputs. |
| * |
| * See Copyright for the status of this software. |
| */ |
| |
| #ifndef XML_DEPRECATED |
| #define XML_DEPRECATED |
| #endif |
| |
| #include <string.h> |
| #include <glob.h> |
| #include <libxml/parser.h> |
| #include <libxml/tree.h> |
| #include <libxml/xmlstring.h> |
| #include "fuzz.h" |
| |
| size_t |
| LLVMFuzzerMutate(char *data, size_t size, size_t maxSize) { |
| (void) data; |
| (void) maxSize; |
| |
| return size; |
| } |
| |
| #ifdef HAVE_HTML_FUZZER |
| int fuzzHtmlInit(int *argc, char ***argv); |
| int fuzzHtml(const char *data, size_t size); |
| size_t fuzzHtmlMutate(char *data, size_t size, size_t maxSize, |
| unsigned seed); |
| #define LLVMFuzzerInitialize fuzzHtmlInit |
| #define LLVMFuzzerTestOneInput fuzzHtml |
| #define LLVMFuzzerCustomMutator fuzzHtmlMutate |
| #include "html.c" |
| #undef LLVMFuzzerInitialize |
| #undef LLVMFuzzerTestOneInput |
| #undef LLVMFuzzerCustomMutator |
| #endif |
| |
| #ifdef HAVE_READER_FUZZER |
| int fuzzReaderInit(int *argc, char ***argv); |
| int fuzzReader(const char *data, size_t size); |
| size_t fuzzReaderMutate(char *data, size_t size, size_t maxSize, |
| unsigned seed); |
| #define LLVMFuzzerInitialize fuzzReaderInit |
| #define LLVMFuzzerTestOneInput fuzzReader |
| #define LLVMFuzzerCustomMutator fuzzReaderMutate |
| #include "reader.c" |
| #undef LLVMFuzzerInitialize |
| #undef LLVMFuzzerTestOneInput |
| #undef LLVMFuzzerCustomMutator |
| #endif |
| |
| #ifdef HAVE_REGEXP_FUZZER |
| int fuzzRegexpInit(int *argc, char ***argv); |
| int fuzzRegexp(const char *data, size_t size); |
| size_t fuzzRegexpMutate(char *data, size_t size, size_t maxSize, |
| unsigned seed); |
| #define LLVMFuzzerInitialize fuzzRegexpInit |
| #define LLVMFuzzerTestOneInput fuzzRegexp |
| #define LLVMFuzzerCustomMutator fuzzRegexpMutate |
| #include "regexp.c" |
| #undef LLVMFuzzerInitialize |
| #undef LLVMFuzzerTestOneInput |
| #undef LLVMFuzzerCustomMutator |
| #endif |
| |
| #ifdef HAVE_SCHEMA_FUZZER |
| int fuzzSchemaInit(int *argc, char ***argv); |
| int fuzzSchema(const char *data, size_t size); |
| size_t fuzzSchemaMutate(char *data, size_t size, size_t maxSize, |
| unsigned seed); |
| #define LLVMFuzzerInitialize fuzzSchemaInit |
| #define LLVMFuzzerTestOneInput fuzzSchema |
| #define LLVMFuzzerCustomMutator fuzzSchemaMutate |
| #include "schema.c" |
| #undef LLVMFuzzerInitialize |
| #undef LLVMFuzzerTestOneInput |
| #undef LLVMFuzzerCustomMutator |
| #endif |
| |
| #ifdef HAVE_URI_FUZZER |
| int fuzzUriInit(int *argc, char ***argv); |
| int fuzzUri(const char *data, size_t size); |
| size_t fuzzUriMutate(char *data, size_t size, size_t maxSize, |
| unsigned seed); |
| #define LLVMFuzzerInitialize fuzzUriInit |
| #define LLVMFuzzerTestOneInput fuzzUri |
| #define LLVMFuzzerCustomMutator fuzzUriMutate |
| #include "uri.c" |
| #undef LLVMFuzzerInitialize |
| #undef LLVMFuzzerTestOneInput |
| #undef LLVMFuzzerCustomMutator |
| #endif |
| |
| #ifdef HAVE_VALID_FUZZER |
| int fuzzValidInit(int *argc, char ***argv); |
| int fuzzValid(const char *data, size_t size); |
| size_t fuzzValidMutate(char *data, size_t size, size_t maxSize, |
| unsigned seed); |
| #define LLVMFuzzerInitialize fuzzValidInit |
| #define LLVMFuzzerTestOneInput fuzzValid |
| #define LLVMFuzzerCustomMutator fuzzValidMutate |
| #include "valid.c" |
| #undef LLVMFuzzerInitialize |
| #undef LLVMFuzzerTestOneInput |
| #undef LLVMFuzzerCustomMutator |
| #endif |
| |
| #ifdef HAVE_XINCLUDE_FUZZER |
| int fuzzXIncludeInit(int *argc, char ***argv); |
| int fuzzXInclude(const char *data, size_t size); |
| size_t fuzzXIncludeMutate(char *data, size_t size, size_t maxSize, |
| unsigned seed); |
| #define LLVMFuzzerInitialize fuzzXIncludeInit |
| #define LLVMFuzzerTestOneInput fuzzXInclude |
| #define LLVMFuzzerCustomMutator fuzzXIncludeMutate |
| #include "xinclude.c" |
| #undef LLVMFuzzerInitialize |
| #undef LLVMFuzzerTestOneInput |
| #undef LLVMFuzzerCustomMutator |
| #endif |
| |
| #ifdef HAVE_XML_FUZZER |
| int fuzzXmlInit(int *argc, char ***argv); |
| int fuzzXml(const char *data, size_t size); |
| size_t fuzzXmlMutate(char *data, size_t size, size_t maxSize, |
| unsigned seed); |
| #define LLVMFuzzerInitialize fuzzXmlInit |
| #define LLVMFuzzerTestOneInput fuzzXml |
| #define LLVMFuzzerCustomMutator fuzzXmlMutate |
| #include "xml.c" |
| #undef LLVMFuzzerInitialize |
| #undef LLVMFuzzerTestOneInput |
| #undef LLVMFuzzerCustomMutator |
| #endif |
| |
| #ifdef HAVE_XPATH_FUZZER |
| int fuzzXPathInit(int *argc, char ***argv); |
| int fuzzXPath(const char *data, size_t size); |
| size_t fuzzXPathMutate(char *data, size_t size, size_t maxSize, |
| unsigned seed); |
| #define LLVMFuzzerInitialize fuzzXPathInit |
| #define LLVMFuzzerTestOneInput fuzzXPath |
| #define LLVMFuzzerCustomMutator fuzzXPathMutate |
| #include "xpath.c" |
| #undef LLVMFuzzerInitialize |
| #undef LLVMFuzzerTestOneInput |
| #undef LLVMFuzzerCustomMutator |
| #endif |
| |
| typedef int |
| (*initFunc)(int *argc, char ***argv); |
| typedef int |
| (*fuzzFunc)(const char *data, size_t size); |
| typedef size_t |
| (*mutateFunc)(char *data, size_t size, size_t maxSize, unsigned seed); |
| |
| int numInputs; |
| |
| static int |
| testFuzzer(initFunc init, fuzzFunc fuzz, mutateFunc mutate, |
| const char *pattern) { |
| glob_t globbuf; |
| int ret = -1; |
| size_t i; |
| |
| (void) mutate; |
| |
| if (glob(pattern, 0, NULL, &globbuf) != 0) { |
| fprintf(stderr, "pattern %s matches no files\n", pattern); |
| return(-1); |
| } |
| |
| if (init != NULL) |
| init(NULL, NULL); |
| |
| for (i = 0; i < globbuf.gl_pathc; i++) { |
| const char *path = globbuf.gl_pathv[i]; |
| char *data; |
| size_t size; |
| |
| data = xmlSlurpFile(path, &size); |
| if (data == NULL) { |
| fprintf(stderr, "couldn't read %s\n", path); |
| goto error; |
| } |
| fuzz(data, size); |
| xmlFree(data); |
| |
| numInputs++; |
| } |
| |
| ret = 0; |
| error: |
| globfree(&globbuf); |
| return(ret); |
| } |
| |
| #ifdef HAVE_XML_FUZZER |
| static int |
| testEntityLoader(void) { |
| xmlParserCtxtPtr ctxt; |
| static const char data[] = |
| "doc.xml\\\n" |
| "<!DOCTYPE doc SYSTEM \"doc.dtd\">\n" |
| "<doc>&ent;</doc>\\\n" |
| "doc.dtd\\\n" |
| "<!ELEMENT doc (#PCDATA)>\n" |
| "<!ENTITY ent SYSTEM \"ent.txt\">\\\n" |
| "ent.txt\\\n" |
| "Hello, world!\\\n"; |
| const char *docBuffer, *url; |
| size_t docSize; |
| xmlDocPtr doc; |
| int ret = 0; |
| |
| xmlFuzzDataInit(data, sizeof(data) - 1); |
| xmlFuzzReadEntities(); |
| |
| url = xmlFuzzMainUrl(); |
| if (strcmp(url, "doc.xml") != 0) { |
| fprintf(stderr, "unexpected main url: %s\n", url); |
| ret = 1; |
| } |
| |
| url = xmlFuzzSecondaryUrl(); |
| if (strcmp(url, "doc.dtd") != 0) { |
| fprintf(stderr, "unexpected secondary url: %s\n", url); |
| ret = 1; |
| } |
| |
| docBuffer = xmlFuzzMainEntity(&docSize); |
| 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 |
| { |
| static xmlChar expected[] = |
| "<?xml version=\"1.0\"?>\n" |
| "<!DOCTYPE doc SYSTEM \"doc.dtd\">\n" |
| "<doc>Hello, world!</doc>\n"; |
| xmlChar *out; |
| |
| xmlDocDumpMemory(doc, &out, NULL); |
| if (xmlStrcmp(out, expected) != 0) { |
| fprintf(stderr, "Expected:\n%sGot:\n%s", expected, out); |
| ret = 1; |
| } |
| xmlFree(out); |
| } |
| #endif |
| |
| xmlFreeDoc(doc); |
| xmlFuzzDataCleanup(); |
| |
| return(ret); |
| } |
| #endif |
| |
| int |
| main(void) { |
| int ret = 0; |
| |
| #ifdef HAVE_XML_FUZZER |
| if (testEntityLoader() != 0) |
| ret = 1; |
| #endif |
| #ifdef HAVE_HTML_FUZZER |
| if (testFuzzer(fuzzHtmlInit, fuzzHtml, fuzzHtmlMutate, |
| "seed/html/*") != 0) |
| ret = 1; |
| #endif |
| #ifdef HAVE_READER_FUZZER |
| if (testFuzzer(fuzzReaderInit, fuzzReader, fuzzReaderMutate, |
| "seed/reader/*") != 0) |
| ret = 1; |
| #endif |
| #ifdef HAVE_REGEXP_FUZZER |
| if (testFuzzer(fuzzRegexpInit, fuzzRegexp, fuzzRegexpMutate, |
| "seed/regexp/*") != 0) |
| ret = 1; |
| #endif |
| #ifdef HAVE_SCHEMA_FUZZER |
| if (testFuzzer(fuzzSchemaInit, fuzzSchema, fuzzSchemaMutate, |
| "seed/schema/*") != 0) |
| ret = 1; |
| #endif |
| #ifdef HAVE_URI_FUZZER |
| if (testFuzzer(fuzzUriInit, fuzzUri, fuzzUriMutate, |
| "seed/uri/*") != 0) |
| ret = 1; |
| #endif |
| #ifdef HAVE_VALID_FUZZER |
| if (testFuzzer(fuzzValidInit, fuzzValid, fuzzValidMutate, |
| "seed/valid/*") != 0) |
| ret = 1; |
| #endif |
| #ifdef HAVE_XINCLUDE_FUZZER |
| if (testFuzzer(fuzzXIncludeInit, fuzzXInclude, fuzzXIncludeMutate, |
| "seed/xinclude/*") != 0) |
| ret = 1; |
| #endif |
| #ifdef HAVE_XML_FUZZER |
| if (testFuzzer(fuzzXmlInit, fuzzXml, fuzzXmlMutate, |
| "seed/xml/*") != 0) |
| ret = 1; |
| #endif |
| #ifdef HAVE_XPATH_FUZZER |
| if (testFuzzer(fuzzXPathInit, fuzzXPath, fuzzXPathMutate, |
| "seed/xpath/*") != 0) |
| ret = 1; |
| #endif |
| |
| if (ret == 0) |
| printf("Successfully tested %d inputs\n", numInputs); |
| |
| return(ret); |
| } |
| |