Line | Count | Source (jump to first uncovered line) |
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 |
16 | | LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED, |
17 | 3.69k | char ***argv ATTRIBUTE_UNUSED) { |
18 | 3.69k | xmlInitParser(); |
19 | 3.69k | #ifdef LIBXML_CATALOG_ENABLED |
20 | 3.69k | xmlInitializeCatalog(); |
21 | 3.69k | #endif |
22 | 3.69k | xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc); |
23 | 3.69k | xmlSetExternalEntityLoader(xmlFuzzEntityLoader); |
24 | | |
25 | 3.69k | return 0; |
26 | 3.69k | } |
27 | | |
28 | | int |
29 | 6.69M | LLVMFuzzerTestOneInput(const char *data, size_t size) { |
30 | 6.69M | static const size_t maxChunkSize = 128; |
31 | 6.69M | xmlDocPtr doc; |
32 | 6.69M | xmlParserCtxtPtr ctxt; |
33 | 6.69M | xmlTextReaderPtr reader; |
34 | 6.69M | xmlChar *out; |
35 | 6.69M | const char *docBuffer, *docUrl; |
36 | 6.69M | size_t maxSize, docSize, consumed, chunkSize; |
37 | 6.69M | int opts, outSize; |
38 | | |
39 | 6.69M | xmlFuzzDataInit(data, size); |
40 | 6.69M | opts = xmlFuzzReadInt(); |
41 | | |
42 | | /* Lower maximum size when processing entities for now. */ |
43 | 6.69M | maxSize = opts & XML_PARSE_NOENT ? 50000 : 500000; |
44 | 6.69M | if (size > maxSize) |
45 | 1.85k | goto exit; |
46 | | |
47 | 6.69M | xmlFuzzReadEntities(); |
48 | 6.69M | docBuffer = xmlFuzzMainEntity(&docSize); |
49 | 6.69M | docUrl = xmlFuzzMainUrl(); |
50 | 6.69M | if (docBuffer == NULL) |
51 | 6.40M | goto exit; |
52 | | |
53 | | /* Pull parser */ |
54 | | |
55 | 295k | doc = xmlReadMemory(docBuffer, docSize, docUrl, NULL, opts); |
56 | 295k | if (opts & XML_PARSE_XINCLUDE) |
57 | 144k | xmlXIncludeProcessFlags(doc, opts); |
58 | | /* Also test the serializer. */ |
59 | 295k | xmlDocDumpMemory(doc, &out, &outSize); |
60 | 295k | xmlFree(out); |
61 | 295k | xmlFreeDoc(doc); |
62 | | |
63 | | /* Push parser */ |
64 | | |
65 | 295k | ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, docUrl); |
66 | 295k | if (ctxt == NULL) |
67 | 0 | goto exit; |
68 | 295k | xmlCtxtUseOptions(ctxt, opts); |
69 | | |
70 | 10.0M | for (consumed = 0; consumed < docSize; consumed += chunkSize) { |
71 | 9.71M | chunkSize = docSize - consumed; |
72 | 9.71M | if (chunkSize > maxChunkSize) |
73 | 9.42M | chunkSize = maxChunkSize; |
74 | 9.71M | xmlParseChunk(ctxt, docBuffer + consumed, chunkSize, 0); |
75 | 9.71M | } |
76 | | |
77 | 295k | xmlParseChunk(ctxt, NULL, 0, 1); |
78 | 295k | if (opts & XML_PARSE_XINCLUDE) |
79 | 144k | xmlXIncludeProcessFlags(ctxt->myDoc, opts); |
80 | 295k | xmlFreeDoc(ctxt->myDoc); |
81 | 295k | xmlFreeParserCtxt(ctxt); |
82 | | |
83 | | /* Reader */ |
84 | | |
85 | 295k | reader = xmlReaderForMemory(docBuffer, docSize, NULL, NULL, opts); |
86 | 295k | if (reader == NULL) |
87 | 0 | goto exit; |
88 | 6.61M | while (xmlTextReaderRead(reader) == 1) { |
89 | 6.31M | if (xmlTextReaderNodeType(reader) == XML_ELEMENT_NODE) { |
90 | 2.31M | int i, n = xmlTextReaderAttributeCount(reader); |
91 | 4.82M | for (i=0; i<n; i++) { |
92 | 2.51M | xmlTextReaderMoveToAttributeNo(reader, i); |
93 | 5.03M | while (xmlTextReaderReadAttributeValue(reader) == 1); |
94 | 2.51M | } |
95 | 2.31M | } |
96 | 6.31M | } |
97 | 295k | xmlFreeTextReader(reader); |
98 | | |
99 | 6.69M | exit: |
100 | 6.69M | xmlFuzzDataCleanup(); |
101 | 6.69M | xmlResetLastError(); |
102 | 6.69M | return(0); |
103 | 295k | } |
104 | | |