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