xref: /aosp_15_r20/external/libxml2/fuzz/valid.c (revision 7c5688314b92172186c154356a6374bf7684c3ca)
1 /*
2  * valid.c: a libFuzzer target to test DTD validation.
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 "fuzz.h"
12 
13 int
LLVMFuzzerInitialize(int * argc ATTRIBUTE_UNUSED,char *** argv ATTRIBUTE_UNUSED)14 LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
15                      char ***argv ATTRIBUTE_UNUSED) {
16     xmlFuzzMemSetup();
17     xmlInitParser();
18 #ifdef LIBXML_CATALOG_ENABLED
19     xmlInitializeCatalog();
20     xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
21 #endif
22 
23     return 0;
24 }
25 
26 int
LLVMFuzzerTestOneInput(const char * data,size_t size)27 LLVMFuzzerTestOneInput(const char *data, size_t size) {
28     xmlParserCtxtPtr ctxt;
29     xmlDocPtr doc;
30     xmlValidCtxtPtr vctxt;
31     const char *docBuffer, *docUrl;
32     size_t maxAlloc, docSize;
33     int opts;
34 
35     xmlFuzzDataInit(data, size);
36     opts = (int) xmlFuzzReadInt(4);
37     opts &= ~XML_PARSE_XINCLUDE;
38     opts |= XML_PARSE_DTDVALID;
39     maxAlloc = xmlFuzzReadInt(4) % (size + 100);
40 
41     xmlFuzzReadEntities();
42     docBuffer = xmlFuzzMainEntity(&docSize);
43     docUrl = xmlFuzzMainUrl();
44     if (docBuffer == NULL)
45         goto exit;
46 
47     /* Pull parser */
48 
49     xmlFuzzMemSetLimit(maxAlloc);
50     ctxt = xmlNewParserCtxt();
51     if (ctxt != NULL) {
52         xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
53         xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
54         doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL, opts);
55         xmlFuzzCheckMallocFailure("xmlCtxtReadMemory",
56                                   ctxt->errNo == XML_ERR_NO_MEMORY);
57         xmlFreeDoc(doc);
58         xmlFreeParserCtxt(ctxt);
59     }
60 
61     /* Post validation */
62 
63     xmlFuzzMemSetLimit(maxAlloc);
64     ctxt = xmlNewParserCtxt();
65     if (ctxt != NULL) {
66         xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
67         xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
68         doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL,
69                                 opts & ~XML_PARSE_DTDVALID);
70         xmlFreeParserCtxt(ctxt);
71 
72         /* Post validation requires global callbacks */
73         xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
74         xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
75         vctxt = xmlNewValidCtxt();
76         xmlValidateDocument(vctxt, doc);
77         xmlFreeValidCtxt(vctxt);
78         xmlFreeDoc(doc);
79         xmlSetGenericErrorFunc(NULL, NULL);
80         xmlSetExternalEntityLoader(NULL);
81     }
82 
83     /* Push parser */
84 
85 #ifdef LIBXML_PUSH_ENABLED
86     {
87         static const size_t maxChunkSize = 128;
88         size_t consumed, chunkSize;
89 
90         xmlFuzzMemSetLimit(maxAlloc);
91         ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, docUrl);
92         if (ctxt != NULL) {
93             xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
94             xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
95             xmlCtxtUseOptions(ctxt, opts);
96 
97             for (consumed = 0; consumed < docSize; consumed += chunkSize) {
98                 chunkSize = docSize - consumed;
99                 if (chunkSize > maxChunkSize)
100                     chunkSize = maxChunkSize;
101                 xmlParseChunk(ctxt, docBuffer + consumed, chunkSize, 0);
102             }
103 
104             xmlParseChunk(ctxt, NULL, 0, 1);
105             xmlFuzzCheckMallocFailure("xmlParseChunk",
106                                       ctxt->errNo == XML_ERR_NO_MEMORY);
107             xmlFreeDoc(ctxt->myDoc);
108             xmlFreeParserCtxt(ctxt);
109         }
110     }
111 #endif
112 
113 exit:
114     xmlFuzzMemSetLimit(0);
115     xmlFuzzDataCleanup();
116     xmlResetLastError();
117     return(0);
118 }
119 
120