xref: /aosp_15_r20/external/libxml2/fuzz/reader.c (revision 7c5688314b92172186c154356a6374bf7684c3ca)
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/xmlreader.h>
12 #include <libxml/xmlsave.h>
13 #include "fuzz.h"
14 
15 #include <string.h>
16 
17 #if 0
18   #define DEBUG
19 #endif
20 
21 typedef enum {
22     OP_READ = 1,
23     OP_READ_INNER_XML,
24     OP_READ_OUTER_XML,
25     OP_READ_STRING,
26     OP_READ_ATTRIBUTE_VALUE,
27     OP_ATTRIBUTE_COUNT,
28     OP_DEPTH,
29     OP_HAS_ATTRIBUTES,
30     OP_HAS_VALUE,
31     OP_IS_DEFAULT,
32     OP_IS_EMPTY_ELEMENT,
33     OP_NODE_TYPE,
34     OP_QUOTE_CHAR,
35     OP_READ_STATE,
36     OP_IS_NAMESPACE_DECL,
37     OP_CONST_BASE_URI,
38     OP_CONST_LOCAL_NAME,
39     OP_CONST_NAME,
40     OP_CONST_NAMESPACE_URI,
41     OP_CONST_PREFIX,
42     OP_CONST_XML_LANG,
43     OP_CONST_VALUE,
44     OP_BASE_URI,
45     OP_LOCAL_NAME,
46     OP_NAME,
47     OP_NAMESPACE_URI,
48     OP_PREFIX,
49     OP_XML_LANG,
50     OP_VALUE,
51     OP_CLOSE,
52     OP_GET_ATTRIBUTE_NO,
53     OP_GET_ATTRIBUTE,
54     OP_GET_ATTRIBUTE_NS,
55     OP_GET_REMAINDER,
56     OP_LOOKUP_NAMESPACE,
57     OP_MOVE_TO_ATTRIBUTE_NO,
58     OP_MOVE_TO_ATTRIBUTE,
59     OP_MOVE_TO_ATTRIBUTE_NS,
60     OP_MOVE_TO_FIRST_ATTRIBUTE,
61     OP_MOVE_TO_NEXT_ATTRIBUTE,
62     OP_MOVE_TO_ELEMENT,
63     OP_NORMALIZATION,
64     OP_CONST_ENCODING,
65     OP_GET_PARSER_PROP,
66     OP_CURRENT_NODE,
67     OP_GET_PARSER_LINE_NUMBER,
68     OP_GET_PARSER_COLUMN_NUMBER,
69     OP_PRESERVE,
70     OP_CURRENT_DOC,
71     OP_EXPAND,
72     OP_NEXT,
73     OP_NEXT_SIBLING,
74     OP_IS_VALID,
75     OP_CONST_XML_VERSION,
76     OP_STANDALONE,
77     OP_BYTE_CONSUMED,
78 
79     OP_MAX
80 } opType;
81 
82 static void
startOp(const char * name)83 startOp(const char *name) {
84     (void) name;
85 #ifdef DEBUG
86     fprintf(stderr, "%s\n", name);
87 #endif
88 }
89 
90 int
LLVMFuzzerInitialize(int * argc ATTRIBUTE_UNUSED,char *** argv ATTRIBUTE_UNUSED)91 LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
92                      char ***argv ATTRIBUTE_UNUSED) {
93     xmlFuzzMemSetup();
94     xmlInitParser();
95 #ifdef LIBXML_CATALOG_ENABLED
96     xmlInitializeCatalog();
97     xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
98 #endif
99 
100     return 0;
101 }
102 
103 int
LLVMFuzzerTestOneInput(const char * data,size_t size)104 LLVMFuzzerTestOneInput(const char *data, size_t size) {
105     xmlTextReaderPtr reader;
106     xmlDocPtr doc = NULL;
107     const xmlError *error;
108     const char *docBuffer;
109     const unsigned char *program;
110     size_t maxAlloc, docSize, programSize, i;
111     size_t totalStringSize = 0;
112     int opts;
113     int oomReport = 0;
114 
115     xmlFuzzDataInit(data, size);
116     opts = (int) xmlFuzzReadInt(4);
117     maxAlloc = xmlFuzzReadInt(4) % (size + 100);
118 
119     program = (const unsigned char *) xmlFuzzReadString(&programSize);
120     if (programSize > 1000)
121         programSize = 1000;
122 
123     xmlFuzzReadEntities();
124     docBuffer = xmlFuzzMainEntity(&docSize);
125     if (docBuffer == NULL)
126         goto exit;
127 
128 #ifdef DEBUG
129     fprintf(stderr, "Input document (%d bytes):\n", (int) docSize);
130     for (i = 0; (size_t) i < docSize; i++) {
131         int c = (unsigned char) docBuffer[i];
132 
133         if ((c == '\n' || (c >= 0x20 && c <= 0x7E)))
134             putc(c, stderr);
135         else
136             fprintf(stderr, "\\x%02X", c);
137     }
138     fprintf(stderr, "\nEOF\n");
139 #endif
140 
141     xmlFuzzMemSetLimit(maxAlloc);
142     reader = xmlReaderForMemory(docBuffer, docSize, NULL, NULL, opts);
143     if (reader == NULL)
144         goto exit;
145 
146     xmlTextReaderSetStructuredErrorHandler(reader, xmlFuzzSErrorFunc, NULL);
147     xmlTextReaderSetResourceLoader(reader, xmlFuzzResourceLoader, NULL);
148 
149     i = 0;
150     while (i < programSize) {
151         int op = program[i++];
152 
153 #define READ_BYTE() (i < programSize ? program[i++] : 0)
154 #define FREE_STRING(str) \
155     do { \
156         if (str != NULL) { \
157             totalStringSize += strlen((char *) str); \
158             xmlFree(str); \
159         } \
160     } while (0)
161 
162         switch (op & 0x3F) {
163             case OP_READ:
164             default:
165                 startOp("Read");
166                 xmlTextReaderRead(reader);
167                 break;
168 
169             case OP_READ_INNER_XML: {
170                 xmlChar *result;
171 
172                 startOp("ReadInnerXml");
173                 result = xmlTextReaderReadInnerXml(reader);
174                 FREE_STRING(result);
175                 break;
176             }
177 
178             case OP_READ_OUTER_XML: {
179                 xmlChar *result;
180 
181                 startOp("ReadOuterXml");
182                 result = xmlTextReaderReadOuterXml(reader);
183                 FREE_STRING(result);
184                 break;
185             }
186 
187             case OP_READ_STRING: {
188                 xmlChar *result;
189 
190                 startOp("ReadString");
191                 result = xmlTextReaderReadString(reader);
192                 FREE_STRING(result);
193                 break;
194             }
195 
196             case OP_READ_ATTRIBUTE_VALUE:
197                 startOp("ReadAttributeValue");
198                 xmlTextReaderReadAttributeValue(reader);
199                 break;
200 
201             case OP_ATTRIBUTE_COUNT:
202                 startOp("AttributeCount");
203                 xmlTextReaderAttributeCount(reader);
204                 break;
205 
206             case OP_DEPTH:
207                 startOp("Depth");
208                 xmlTextReaderDepth(reader);
209                 break;
210 
211             case OP_HAS_ATTRIBUTES:
212                 startOp("HasAttributes");
213                 xmlTextReaderHasAttributes(reader);
214                 break;
215 
216             case OP_HAS_VALUE:
217                 startOp("HasValue");
218                 xmlTextReaderHasValue(reader);
219                 break;
220 
221             case OP_IS_DEFAULT:
222                 startOp("IsDefault");
223                 xmlTextReaderIsDefault(reader);
224                 break;
225 
226             case OP_IS_EMPTY_ELEMENT:
227                 startOp("IsEmptyElement");
228                 xmlTextReaderIsEmptyElement(reader);
229                 break;
230 
231             case OP_NODE_TYPE:
232                 startOp("NodeType");
233                 xmlTextReaderNodeType(reader);
234                 break;
235 
236             case OP_QUOTE_CHAR:
237                 startOp("QuoteChar");
238                 xmlTextReaderQuoteChar(reader);
239                 break;
240 
241             case OP_READ_STATE:
242                 startOp("ReadState");
243                 xmlTextReaderReadState(reader);
244                 break;
245 
246             case OP_IS_NAMESPACE_DECL:
247                 startOp("IsNamespaceDecl");
248                 xmlTextReaderIsNamespaceDecl(reader);
249                 break;
250 
251             case OP_CONST_BASE_URI:
252                 startOp("ConstBaseUri");
253                 xmlTextReaderConstBaseUri(reader);
254                 break;
255 
256             case OP_CONST_LOCAL_NAME:
257                 startOp("ConstLocalName");
258                 xmlTextReaderConstLocalName(reader);
259                 break;
260 
261             case OP_CONST_NAME:
262                 startOp("ConstName");
263                 xmlTextReaderConstName(reader);
264                 break;
265 
266             case OP_CONST_NAMESPACE_URI:
267                 startOp("ConstNamespaceUri");
268                 xmlTextReaderConstNamespaceUri(reader);
269                 break;
270 
271             case OP_CONST_PREFIX:
272                 startOp("ConstPrefix");
273                 xmlTextReaderConstPrefix(reader);
274                 break;
275 
276             case OP_CONST_XML_LANG:
277                 startOp("ConstXmlLang");
278                 xmlTextReaderConstXmlLang(reader);
279                 oomReport = -1;
280                 break;
281 
282             case OP_CONST_VALUE:
283                 startOp("ConstValue");
284                 xmlTextReaderConstValue(reader);
285                 break;
286 
287             case OP_BASE_URI: {
288                 xmlChar *result;
289 
290                 startOp("BaseUri");
291                 result = xmlTextReaderBaseUri(reader);
292                 FREE_STRING(result);
293                 break;
294             }
295 
296             case OP_LOCAL_NAME: {
297                 xmlChar *result;
298 
299                 startOp("LocalName");
300                 result = xmlTextReaderLocalName(reader);
301                 FREE_STRING(result);
302                 break;
303             }
304 
305             case OP_NAME: {
306                 xmlChar *result;
307 
308                 startOp("Name");
309                 result = xmlTextReaderName(reader);
310                 FREE_STRING(result);
311                 break;
312             }
313 
314             case OP_NAMESPACE_URI: {
315                 xmlChar *result;
316 
317                 startOp("NamespaceUri");
318                 result = xmlTextReaderNamespaceUri(reader);
319                 FREE_STRING(result);
320                 break;
321             }
322 
323             case OP_PREFIX: {
324                 xmlChar *result;
325 
326                 startOp("Prefix");
327                 result = xmlTextReaderPrefix(reader);
328                 FREE_STRING(result);
329                 break;
330             }
331 
332             case OP_XML_LANG: {
333                 xmlChar *result;
334 
335                 startOp("XmlLang");
336                 result = xmlTextReaderXmlLang(reader);
337                 oomReport = -1;
338                 FREE_STRING(result);
339                 break;
340             }
341 
342             case OP_VALUE: {
343                 xmlChar *result;
344 
345                 startOp("Value");
346                 result = xmlTextReaderValue(reader);
347                 FREE_STRING(result);
348                 break;
349             }
350 
351             case OP_CLOSE:
352                 startOp("Close");
353                 if (doc == NULL)
354                     doc = xmlTextReaderCurrentDoc(reader);
355                 xmlTextReaderClose(reader);
356                 break;
357 
358             case OP_GET_ATTRIBUTE_NO: {
359                 xmlChar *result;
360                 int no = READ_BYTE();
361 
362                 startOp("GetAttributeNo");
363                 result = xmlTextReaderGetAttributeNo(reader, no);
364                 FREE_STRING(result);
365                 break;
366             }
367 
368             case OP_GET_ATTRIBUTE: {
369                 const xmlChar *name = xmlTextReaderConstName(reader);
370                 xmlChar *result;
371 
372                 startOp("GetAttribute");
373                 result = xmlTextReaderGetAttribute(reader, name);
374                 FREE_STRING(result);
375                 break;
376             }
377 
378             case OP_GET_ATTRIBUTE_NS: {
379                 const xmlChar *localName, *namespaceUri;
380                 xmlChar *result;
381 
382                 startOp("GetAttributeNs");
383                 localName = xmlTextReaderConstLocalName(reader);
384                 namespaceUri = xmlTextReaderConstNamespaceUri(reader);
385                 result = xmlTextReaderGetAttributeNs(reader, localName,
386                                                      namespaceUri);
387                 FREE_STRING(result);
388                 break;
389             }
390 
391             case OP_GET_REMAINDER:
392                 startOp("GetRemainder");
393                 if (doc == NULL)
394                     doc = xmlTextReaderCurrentDoc(reader);
395                 xmlFreeParserInputBuffer(xmlTextReaderGetRemainder(reader));
396                 break;
397 
398             case OP_LOOKUP_NAMESPACE: {
399                 const xmlChar *prefix = xmlTextReaderConstPrefix(reader);
400                 xmlChar *result;
401 
402                 startOp("LookupNamespace");
403                 result = xmlTextReaderLookupNamespace(reader, prefix);
404                 FREE_STRING(result);
405                 break;
406             }
407 
408             case OP_MOVE_TO_ATTRIBUTE_NO: {
409                 int no = READ_BYTE();
410 
411                 startOp("MoveToAttributeNo");
412                 xmlTextReaderMoveToAttributeNo(reader, no);
413                 break;
414             }
415 
416             case OP_MOVE_TO_ATTRIBUTE: {
417                 const xmlChar *name = xmlTextReaderConstName(reader);
418 
419                 startOp("MoveToAttribute");
420                 xmlTextReaderMoveToAttribute(reader, name);
421                 break;
422             }
423 
424             case OP_MOVE_TO_ATTRIBUTE_NS: {
425                 const xmlChar *localName, *namespaceUri;
426 
427                 startOp("MoveToAttributeNs");
428                 localName = xmlTextReaderConstLocalName(reader);
429                 namespaceUri = xmlTextReaderConstNamespaceUri(reader);
430                 xmlTextReaderMoveToAttributeNs(reader, localName,
431                                                namespaceUri);
432                 break;
433             }
434 
435             case OP_MOVE_TO_FIRST_ATTRIBUTE:
436                 startOp("MoveToFirstAttribute");
437                 xmlTextReaderMoveToFirstAttribute(reader);
438                 break;
439 
440             case OP_MOVE_TO_NEXT_ATTRIBUTE:
441                 startOp("MoveToNextAttribute");
442                 xmlTextReaderMoveToNextAttribute(reader);
443                 break;
444 
445             case OP_MOVE_TO_ELEMENT:
446                 startOp("MoveToElement");
447                 xmlTextReaderMoveToElement(reader);
448                 break;
449 
450             case OP_NORMALIZATION:
451                 startOp("Normalization");
452                 xmlTextReaderNormalization(reader);
453                 break;
454 
455             case OP_CONST_ENCODING:
456                 startOp("ConstEncoding");
457                 xmlTextReaderConstEncoding(reader);
458                 break;
459 
460             case OP_GET_PARSER_PROP: {
461                 int prop = READ_BYTE();
462 
463                 startOp("GetParserProp");
464                 xmlTextReaderGetParserProp(reader, prop);
465                 break;
466             }
467 
468             case OP_CURRENT_NODE:
469                 startOp("CurrentNode");
470                 xmlTextReaderCurrentNode(reader);
471                 break;
472 
473             case OP_GET_PARSER_LINE_NUMBER:
474                 startOp("GetParserLineNumber");
475                 xmlTextReaderGetParserLineNumber(reader);
476                 break;
477 
478             case OP_GET_PARSER_COLUMN_NUMBER:
479                 startOp("GetParserColumnNumber");
480                 xmlTextReaderGetParserColumnNumber(reader);
481                 break;
482 
483             case OP_PRESERVE:
484                 startOp("Preserve");
485                 xmlTextReaderPreserve(reader);
486                 break;
487 
488             case OP_CURRENT_DOC: {
489                 xmlDocPtr result;
490 
491                 startOp("CurrentDoc");
492                 result = xmlTextReaderCurrentDoc(reader);
493                 if (doc == NULL)
494                     doc = result;
495                 break;
496             }
497 
498             case OP_EXPAND:
499                 startOp("Expand");
500                 xmlTextReaderExpand(reader);
501                 break;
502 
503             case OP_NEXT:
504                 startOp("Next");
505                 xmlTextReaderNext(reader);
506                 break;
507 
508             case OP_NEXT_SIBLING:
509                 startOp("NextSibling");
510                 xmlTextReaderNextSibling(reader);
511                 break;
512 
513             case OP_IS_VALID:
514                 startOp("IsValid");
515                 xmlTextReaderIsValid(reader);
516                 break;
517 
518             case OP_CONST_XML_VERSION:
519                 startOp("ConstXmlVersion");
520                 xmlTextReaderConstXmlVersion(reader);
521                 break;
522 
523             case OP_STANDALONE:
524                 startOp("Standalone");
525                 xmlTextReaderStandalone(reader);
526                 break;
527 
528             case OP_BYTE_CONSUMED:
529                 startOp("ByteConsumed");
530                 xmlTextReaderByteConsumed(reader);
531                 oomReport = -1;
532                 break;
533         }
534 
535         if (totalStringSize > docSize * 2)
536             break;
537     }
538 
539     error = xmlTextReaderGetLastError(reader);
540     if (error->code == XML_ERR_NO_MEMORY)
541         oomReport = 1;
542     xmlFuzzCheckMallocFailure("reader", oomReport);
543 
544     xmlFreeTextReader(reader);
545 
546     if (doc != NULL)
547         xmlFreeDoc(doc);
548 
549 exit:
550     xmlFuzzMemSetLimit(0);
551     xmlFuzzDataCleanup();
552     xmlResetLastError();
553     return(0);
554 }
555 
556