xref: /aosp_15_r20/external/libxml2/fuzz/lint.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 <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