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