1 /*
2  * xml.c: a libFuzzer target to test several XML parser interfaces.
3  *
4  * See Copyright for the status of this software.
5  */
6 
7 #include <libxml/catalog.h>
8 #include <libxml/parser.h>
9 #include <libxml/tree.h>
10 #include <libxml/xmlerror.h>
11 #include <libxml/xinclude.h>
12 #include <libxml/xmlreader.h>
13 #include "fuzz.h"
14 
15 int
LLVMFuzzerInitialize(int * argc ATTRIBUTE_UNUSED,char *** argv ATTRIBUTE_UNUSED)16 LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
17                      char ***argv ATTRIBUTE_UNUSED) {
18     xmlInitParser();
19 #ifdef LIBXML_CATALOG_ENABLED
20     xmlInitializeCatalog();
21 #endif
22     xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
23     xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
24 
25     return 0;
26 }
27 
28 int
LLVMFuzzerTestOneInput(const char * data,size_t size)29 LLVMFuzzerTestOneInput(const char *data, size_t size) {
30     static const size_t maxChunkSize = 128;
31     xmlDocPtr doc;
32     xmlParserCtxtPtr ctxt;
33     xmlTextReaderPtr reader;
34     xmlChar *out;
35     const char *docBuffer, *docUrl;
36     size_t maxSize, docSize, consumed, chunkSize;
37     int opts, outSize;
38 
39     xmlFuzzDataInit(data, size);
40     opts = xmlFuzzReadInt();
41 
42     /* Lower maximum size when processing entities for now. */
43     maxSize = opts & XML_PARSE_NOENT ? 50000 : 500000;
44     if (size > maxSize)
45         goto exit;
46 
47     xmlFuzzReadEntities();
48     docBuffer = xmlFuzzMainEntity(&docSize);
49     docUrl = xmlFuzzMainUrl();
50     if (docBuffer == NULL)
51         goto exit;
52 
53     /* Pull parser */
54 
55     doc = xmlReadMemory(docBuffer, docSize, docUrl, NULL, opts);
56     if (opts & XML_PARSE_XINCLUDE)
57         xmlXIncludeProcessFlags(doc, opts);
58     /* Also test the serializer. */
59     xmlDocDumpMemory(doc, &out, &outSize);
60     xmlFree(out);
61     xmlFreeDoc(doc);
62 
63     /* Push parser */
64 
65     ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, docUrl);
66     if (ctxt == NULL)
67         goto exit;
68     xmlCtxtUseOptions(ctxt, opts);
69 
70     for (consumed = 0; consumed < docSize; consumed += chunkSize) {
71         chunkSize = docSize - consumed;
72         if (chunkSize > maxChunkSize)
73             chunkSize = maxChunkSize;
74         xmlParseChunk(ctxt, docBuffer + consumed, chunkSize, 0);
75     }
76 
77     xmlParseChunk(ctxt, NULL, 0, 1);
78     if (opts & XML_PARSE_XINCLUDE)
79         xmlXIncludeProcessFlags(ctxt->myDoc, opts);
80     xmlFreeDoc(ctxt->myDoc);
81     xmlFreeParserCtxt(ctxt);
82 
83     /* Reader */
84 
85     reader = xmlReaderForMemory(docBuffer, docSize, NULL, NULL, opts);
86     if (reader == NULL)
87         goto exit;
88     while (xmlTextReaderRead(reader) == 1) {
89         if (xmlTextReaderNodeType(reader) == XML_ELEMENT_NODE) {
90             int i, n = xmlTextReaderAttributeCount(reader);
91             for (i=0; i<n; i++) {
92                 xmlTextReaderMoveToAttributeNo(reader, i);
93                 while (xmlTextReaderReadAttributeValue(reader) == 1);
94             }
95         }
96     }
97     xmlFreeTextReader(reader);
98 
99 exit:
100     xmlFuzzDataCleanup();
101     xmlResetLastError();
102     return(0);
103 }
104 
105