1*7c568831SAndroid Build Coastguard Worker /*
2*7c568831SAndroid Build Coastguard Worker * xml.c: a libFuzzer target to test several XML parser interfaces.
3*7c568831SAndroid Build Coastguard Worker *
4*7c568831SAndroid Build Coastguard Worker * See Copyright for the status of this software.
5*7c568831SAndroid Build Coastguard Worker */
6*7c568831SAndroid Build Coastguard Worker
7*7c568831SAndroid Build Coastguard Worker #include <fcntl.h>
8*7c568831SAndroid Build Coastguard Worker #include <stdlib.h>
9*7c568831SAndroid Build Coastguard Worker #include <stdio.h>
10*7c568831SAndroid Build Coastguard Worker #include <unistd.h>
11*7c568831SAndroid Build Coastguard Worker
12*7c568831SAndroid Build Coastguard Worker #include <libxml/catalog.h>
13*7c568831SAndroid Build Coastguard Worker #include <libxml/parser.h>
14*7c568831SAndroid Build Coastguard Worker #include <libxml/xmlerror.h>
15*7c568831SAndroid Build Coastguard Worker #include <libxml/xmlmemory.h>
16*7c568831SAndroid Build Coastguard Worker
17*7c568831SAndroid Build Coastguard Worker #include "fuzz.h"
18*7c568831SAndroid Build Coastguard Worker
19*7c568831SAndroid Build Coastguard Worker #define XMLLINT_FUZZ
20*7c568831SAndroid Build Coastguard Worker #include "../xmllint.c"
21*7c568831SAndroid Build Coastguard Worker
22*7c568831SAndroid Build Coastguard Worker static const char *const switches[] = {
23*7c568831SAndroid Build Coastguard Worker "--auto",
24*7c568831SAndroid Build Coastguard Worker "--c14n",
25*7c568831SAndroid Build Coastguard Worker "--c14n11",
26*7c568831SAndroid Build Coastguard Worker "--compress",
27*7c568831SAndroid Build Coastguard Worker "--copy",
28*7c568831SAndroid Build Coastguard Worker "--debug",
29*7c568831SAndroid Build Coastguard Worker "--debugent",
30*7c568831SAndroid Build Coastguard Worker "--dropdtd",
31*7c568831SAndroid Build Coastguard Worker "--dtdattr",
32*7c568831SAndroid Build Coastguard Worker "--exc-c14n",
33*7c568831SAndroid Build Coastguard Worker "--format",
34*7c568831SAndroid Build Coastguard Worker "--htmlout",
35*7c568831SAndroid Build Coastguard Worker "--huge",
36*7c568831SAndroid Build Coastguard Worker "--insert",
37*7c568831SAndroid Build Coastguard Worker "--loaddtd",
38*7c568831SAndroid Build Coastguard Worker "--load-trace",
39*7c568831SAndroid Build Coastguard Worker "--memory",
40*7c568831SAndroid Build Coastguard Worker "--noblanks",
41*7c568831SAndroid Build Coastguard Worker "--nocdata",
42*7c568831SAndroid Build Coastguard Worker "--nocompact",
43*7c568831SAndroid Build Coastguard Worker "--nodefdtd",
44*7c568831SAndroid Build Coastguard Worker "--nodict",
45*7c568831SAndroid Build Coastguard Worker "--noenc",
46*7c568831SAndroid Build Coastguard Worker "--noent",
47*7c568831SAndroid Build Coastguard Worker "--nofixup-base-uris",
48*7c568831SAndroid Build Coastguard Worker "--nonet",
49*7c568831SAndroid Build Coastguard Worker "--noout",
50*7c568831SAndroid Build Coastguard Worker "--nowarning",
51*7c568831SAndroid Build Coastguard Worker "--nowrap",
52*7c568831SAndroid Build Coastguard Worker "--noxincludenode",
53*7c568831SAndroid Build Coastguard Worker "--nsclean",
54*7c568831SAndroid Build Coastguard Worker "--oldxml10",
55*7c568831SAndroid Build Coastguard Worker "--pedantic",
56*7c568831SAndroid Build Coastguard Worker "--postvalid",
57*7c568831SAndroid Build Coastguard Worker "--push",
58*7c568831SAndroid Build Coastguard Worker "--pushsmall",
59*7c568831SAndroid Build Coastguard Worker "--quiet",
60*7c568831SAndroid Build Coastguard Worker "--recover",
61*7c568831SAndroid Build Coastguard Worker "--sax1",
62*7c568831SAndroid Build Coastguard Worker "--testIO",
63*7c568831SAndroid Build Coastguard Worker "--timing",
64*7c568831SAndroid Build Coastguard Worker "--valid",
65*7c568831SAndroid Build Coastguard Worker "--version",
66*7c568831SAndroid Build Coastguard Worker "--walker",
67*7c568831SAndroid Build Coastguard Worker "--xinclude",
68*7c568831SAndroid Build Coastguard Worker "--xmlout"
69*7c568831SAndroid Build Coastguard Worker };
70*7c568831SAndroid Build Coastguard Worker static const size_t numSwitches = sizeof(switches) / sizeof(switches[0]);
71*7c568831SAndroid Build Coastguard Worker
72*7c568831SAndroid Build Coastguard Worker struct {
73*7c568831SAndroid Build Coastguard Worker const char **argv;
74*7c568831SAndroid Build Coastguard Worker size_t argi;
75*7c568831SAndroid Build Coastguard Worker } vars;
76*7c568831SAndroid Build Coastguard Worker
77*7c568831SAndroid Build Coastguard Worker static void
pushArg(const char * str)78*7c568831SAndroid Build Coastguard Worker pushArg(const char *str) {
79*7c568831SAndroid Build Coastguard Worker vars.argv[vars.argi++] = str;
80*7c568831SAndroid Build Coastguard Worker }
81*7c568831SAndroid Build Coastguard Worker
82*7c568831SAndroid Build Coastguard Worker int
LLVMFuzzerInitialize(int * argc ATTRIBUTE_UNUSED,char *** argv ATTRIBUTE_UNUSED)83*7c568831SAndroid Build Coastguard Worker LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
84*7c568831SAndroid Build Coastguard Worker char ***argv ATTRIBUTE_UNUSED) {
85*7c568831SAndroid Build Coastguard Worker int fd;
86*7c568831SAndroid Build Coastguard Worker
87*7c568831SAndroid Build Coastguard Worker /* Redirect stdout to /dev/null */
88*7c568831SAndroid Build Coastguard Worker fd = open("/dev/null", O_WRONLY);
89*7c568831SAndroid Build Coastguard Worker if (fd == -1) {
90*7c568831SAndroid Build Coastguard Worker perror("/dev/null");
91*7c568831SAndroid Build Coastguard Worker abort();
92*7c568831SAndroid Build Coastguard Worker }
93*7c568831SAndroid Build Coastguard Worker if (dup2(fd, STDOUT_FILENO) == -1) {
94*7c568831SAndroid Build Coastguard Worker perror("dup2");
95*7c568831SAndroid Build Coastguard Worker abort();
96*7c568831SAndroid Build Coastguard Worker }
97*7c568831SAndroid Build Coastguard Worker close(fd);
98*7c568831SAndroid Build Coastguard Worker
99*7c568831SAndroid Build Coastguard Worker return 0;
100*7c568831SAndroid Build Coastguard Worker }
101*7c568831SAndroid Build Coastguard Worker
102*7c568831SAndroid Build Coastguard Worker int
LLVMFuzzerTestOneInput(const char * data,size_t size)103*7c568831SAndroid Build Coastguard Worker LLVMFuzzerTestOneInput(const char *data, size_t size) {
104*7c568831SAndroid Build Coastguard Worker char maxmemBuf[20];
105*7c568831SAndroid Build Coastguard Worker char maxAmplBuf[20];
106*7c568831SAndroid Build Coastguard Worker char prettyBuf[20];
107*7c568831SAndroid Build Coastguard Worker const char *sval, *docBuffer, *docUrl;
108*7c568831SAndroid Build Coastguard Worker size_t ssize, docSize, i;
109*7c568831SAndroid Build Coastguard Worker unsigned uval;
110*7c568831SAndroid Build Coastguard Worker int ival;
111*7c568831SAndroid Build Coastguard Worker
112*7c568831SAndroid Build Coastguard Worker vars.argv = malloc((numSwitches + 5 + 6 * 2) * sizeof(vars.argv[0]));
113*7c568831SAndroid Build Coastguard Worker vars.argi = 0;
114*7c568831SAndroid Build Coastguard Worker pushArg("xmllint"),
115*7c568831SAndroid Build Coastguard Worker pushArg("--nocatalogs");
116*7c568831SAndroid Build Coastguard Worker
117*7c568831SAndroid Build Coastguard Worker xmlFuzzDataInit(data, size);
118*7c568831SAndroid Build Coastguard Worker
119*7c568831SAndroid Build Coastguard Worker for (i = 0; i < numSwitches; i++) {
120*7c568831SAndroid Build Coastguard Worker if (i % 32 == 0)
121*7c568831SAndroid Build Coastguard Worker uval = xmlFuzzReadInt(4);
122*7c568831SAndroid Build Coastguard Worker if ((uval & 1) && (switches[i] != NULL))
123*7c568831SAndroid Build Coastguard Worker pushArg(switches[i]);
124*7c568831SAndroid Build Coastguard Worker uval >>= 1;
125*7c568831SAndroid Build Coastguard Worker }
126*7c568831SAndroid Build Coastguard Worker
127*7c568831SAndroid Build Coastguard Worker /*
128*7c568831SAndroid Build Coastguard Worker * Use four main parsing modes with equal probability
129*7c568831SAndroid Build Coastguard Worker */
130*7c568831SAndroid Build Coastguard Worker switch (uval & 3) {
131*7c568831SAndroid Build Coastguard Worker case 0:
132*7c568831SAndroid Build Coastguard Worker /* XML parser */
133*7c568831SAndroid Build Coastguard Worker break;
134*7c568831SAndroid Build Coastguard Worker case 1:
135*7c568831SAndroid Build Coastguard Worker /* HTML parser */
136*7c568831SAndroid Build Coastguard Worker pushArg("--html");
137*7c568831SAndroid Build Coastguard Worker break;
138*7c568831SAndroid Build Coastguard Worker case 2:
139*7c568831SAndroid Build Coastguard Worker /* XML reader */
140*7c568831SAndroid Build Coastguard Worker pushArg("--stream");
141*7c568831SAndroid Build Coastguard Worker break;
142*7c568831SAndroid Build Coastguard Worker case 3:
143*7c568831SAndroid Build Coastguard Worker /* SAX parser */
144*7c568831SAndroid Build Coastguard Worker pushArg("--sax");
145*7c568831SAndroid Build Coastguard Worker break;
146*7c568831SAndroid Build Coastguard Worker }
147*7c568831SAndroid Build Coastguard Worker
148*7c568831SAndroid Build Coastguard Worker uval = xmlFuzzReadInt(4);
149*7c568831SAndroid Build Coastguard Worker if (uval > 0) {
150*7c568831SAndroid Build Coastguard Worker if (size <= (INT_MAX - 2000) / 20)
151*7c568831SAndroid Build Coastguard Worker uval %= size * 20 + 2000;
152*7c568831SAndroid Build Coastguard Worker else
153*7c568831SAndroid Build Coastguard Worker uval %= INT_MAX;
154*7c568831SAndroid Build Coastguard Worker snprintf(maxmemBuf, 20, "%u", uval);
155*7c568831SAndroid Build Coastguard Worker pushArg("--maxmem");
156*7c568831SAndroid Build Coastguard Worker pushArg(maxmemBuf);
157*7c568831SAndroid Build Coastguard Worker }
158*7c568831SAndroid Build Coastguard Worker
159*7c568831SAndroid Build Coastguard Worker ival = xmlFuzzReadInt(1);
160*7c568831SAndroid Build Coastguard Worker if (ival >= 1 && ival <= 5) {
161*7c568831SAndroid Build Coastguard Worker snprintf(maxAmplBuf, 20, "%d", ival);
162*7c568831SAndroid Build Coastguard Worker pushArg("--max-ampl");
163*7c568831SAndroid Build Coastguard Worker pushArg(maxAmplBuf);
164*7c568831SAndroid Build Coastguard Worker }
165*7c568831SAndroid Build Coastguard Worker
166*7c568831SAndroid Build Coastguard Worker ival = xmlFuzzReadInt(1);
167*7c568831SAndroid Build Coastguard Worker if (ival != 0) {
168*7c568831SAndroid Build Coastguard Worker snprintf(prettyBuf, 20, "%d", ival - 128);
169*7c568831SAndroid Build Coastguard Worker pushArg("--pretty");
170*7c568831SAndroid Build Coastguard Worker pushArg(prettyBuf);
171*7c568831SAndroid Build Coastguard Worker }
172*7c568831SAndroid Build Coastguard Worker
173*7c568831SAndroid Build Coastguard Worker sval = xmlFuzzReadString(&ssize);
174*7c568831SAndroid Build Coastguard Worker if (ssize > 0) {
175*7c568831SAndroid Build Coastguard Worker pushArg("--encode");
176*7c568831SAndroid Build Coastguard Worker pushArg(sval);
177*7c568831SAndroid Build Coastguard Worker }
178*7c568831SAndroid Build Coastguard Worker
179*7c568831SAndroid Build Coastguard Worker sval = xmlFuzzReadString(&ssize);
180*7c568831SAndroid Build Coastguard Worker if (ssize > 0) {
181*7c568831SAndroid Build Coastguard Worker pushArg("--pattern");
182*7c568831SAndroid Build Coastguard Worker pushArg(sval);
183*7c568831SAndroid Build Coastguard Worker }
184*7c568831SAndroid Build Coastguard Worker
185*7c568831SAndroid Build Coastguard Worker sval = xmlFuzzReadString(&ssize);
186*7c568831SAndroid Build Coastguard Worker if (ssize > 0) {
187*7c568831SAndroid Build Coastguard Worker pushArg("--xpath");
188*7c568831SAndroid Build Coastguard Worker pushArg(sval);
189*7c568831SAndroid Build Coastguard Worker }
190*7c568831SAndroid Build Coastguard Worker
191*7c568831SAndroid Build Coastguard Worker xmlFuzzReadEntities();
192*7c568831SAndroid Build Coastguard Worker docBuffer = xmlFuzzMainEntity(&docSize);
193*7c568831SAndroid Build Coastguard Worker docUrl = xmlFuzzMainUrl();
194*7c568831SAndroid Build Coastguard Worker if (docBuffer == NULL || docUrl[0] == '-')
195*7c568831SAndroid Build Coastguard Worker goto exit;
196*7c568831SAndroid Build Coastguard Worker pushArg(docUrl);
197*7c568831SAndroid Build Coastguard Worker
198*7c568831SAndroid Build Coastguard Worker pushArg(NULL);
199*7c568831SAndroid Build Coastguard Worker
200*7c568831SAndroid Build Coastguard Worker xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
201*7c568831SAndroid Build Coastguard Worker #ifdef LIBXML_CATALOG_ENABLED
202*7c568831SAndroid Build Coastguard Worker xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
203*7c568831SAndroid Build Coastguard Worker #endif
204*7c568831SAndroid Build Coastguard Worker
205*7c568831SAndroid Build Coastguard Worker xmllintMain(vars.argi - 1, vars.argv, xmlFuzzResourceLoader);
206*7c568831SAndroid Build Coastguard Worker
207*7c568831SAndroid Build Coastguard Worker xmlMemSetup(free, malloc, realloc, xmlMemStrdup);
208*7c568831SAndroid Build Coastguard Worker
209*7c568831SAndroid Build Coastguard Worker exit:
210*7c568831SAndroid Build Coastguard Worker xmlFuzzDataCleanup();
211*7c568831SAndroid Build Coastguard Worker free(vars.argv);
212*7c568831SAndroid Build Coastguard Worker return(0);
213*7c568831SAndroid Build Coastguard Worker }
214