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