VirtualBox

source: vbox/trunk/src/libs/libxml2-2.13.2/fuzz/fuzz.c@ 107351

Last change on this file since 107351 was 105420, checked in by vboxsync, 6 months ago

libxml2-2.12.6: Applied and adjusted our libxml2 changes to 2.12.6. bugref:10730

  • Property svn:eol-style set to native
File size: 9.7 KB
Line 
1/*
2 * fuzz.c: Common functions for fuzzing.
3 *
4 * See Copyright for the status of this software.
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/stat.h>
11
12#include <libxml/hash.h>
13#include <libxml/parser.h>
14#include <libxml/parserInternals.h>
15#include <libxml/tree.h>
16#include <libxml/xmlIO.h>
17#include "fuzz.h"
18
19typedef struct {
20 const char *data;
21 size_t size;
22} xmlFuzzEntityInfo;
23
24/* Single static instance for now */
25static struct {
26 /* Original data */
27 const char *data;
28 size_t size;
29
30 /* Remaining data */
31 const char *ptr;
32 size_t remaining;
33
34 /* Buffer for unescaped strings */
35 char *outBuf;
36 char *outPtr; /* Free space at end of buffer */
37
38 xmlHashTablePtr entities; /* Maps URLs to xmlFuzzEntityInfos */
39
40 /* The first entity is the main entity. */
41 const char *mainUrl;
42 xmlFuzzEntityInfo *mainEntity;
43} fuzzData;
44
45size_t fuzzNumAllocs;
46size_t fuzzMaxAllocs;
47int fuzzAllocFailed;
48
49/**
50 * xmlFuzzErrorFunc:
51 *
52 * An error function that simply discards all errors.
53 */
54void
55xmlFuzzErrorFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg ATTRIBUTE_UNUSED,
56 ...) {
57}
58
59/*
60 * Malloc failure injection.
61 *
62 * To debug issues involving malloc failures, it's often helpful to set
63 * MALLOC_ABORT to 1. This should provide a backtrace of the failed
64 * allocation.
65 */
66
67#define XML_FUZZ_MALLOC_ABORT 0
68
69static void *
70xmlFuzzMalloc(size_t size) {
71 void *ret;
72
73 if (fuzzMaxAllocs > 0) {
74 fuzzNumAllocs += 1;
75 if (fuzzNumAllocs == fuzzMaxAllocs) {
76#if XML_FUZZ_MALLOC_ABORT
77 abort();
78#endif
79 fuzzAllocFailed = 1;
80 return NULL;
81 }
82 }
83
84 ret = malloc(size);
85 if (ret == NULL)
86 fuzzAllocFailed = 1;
87
88 return ret;
89}
90
91static void *
92xmlFuzzRealloc(void *ptr, size_t size) {
93 void *ret;
94
95 if (fuzzMaxAllocs > 0) {
96 fuzzNumAllocs += 1;
97 if (fuzzNumAllocs == fuzzMaxAllocs) {
98#if XML_FUZZ_MALLOC_ABORT
99 abort();
100#endif
101 fuzzAllocFailed = 1;
102 return NULL;
103 }
104 }
105
106 ret = realloc(ptr, size);
107 if (ret == NULL)
108 fuzzAllocFailed = 1;
109
110 return ret;
111}
112
113void
114xmlFuzzMemSetup(void) {
115 xmlMemSetup(free, xmlFuzzMalloc, xmlFuzzRealloc, xmlMemStrdup);
116}
117
118void
119xmlFuzzMemSetLimit(size_t limit) {
120 fuzzNumAllocs = 0;
121 fuzzMaxAllocs = limit;
122 fuzzAllocFailed = 0;
123}
124
125int
126xmlFuzzMallocFailed(void) {
127 return fuzzAllocFailed;
128}
129
130void
131xmlFuzzResetMallocFailed(void) {
132 fuzzAllocFailed = 0;
133}
134
135void
136xmlFuzzCheckMallocFailure(const char *func, int error) {
137 if (error >= 0 && fuzzAllocFailed != error) {
138 fprintf(stderr, "%s: malloc failure %s reported\n",
139 func, fuzzAllocFailed ? "not" : "erroneously");
140 abort();
141 }
142 fuzzAllocFailed = 0;
143}
144
145/**
146 * xmlFuzzDataInit:
147 *
148 * Initialize fuzz data provider.
149 */
150void
151xmlFuzzDataInit(const char *data, size_t size) {
152 fuzzData.data = data;
153 fuzzData.size = size;
154 fuzzData.ptr = data;
155 fuzzData.remaining = size;
156
157 fuzzData.outBuf = xmlMalloc(size + 1);
158 fuzzData.outPtr = fuzzData.outBuf;
159
160 fuzzData.entities = xmlHashCreate(8);
161 fuzzData.mainUrl = NULL;
162 fuzzData.mainEntity = NULL;
163}
164
165/**
166 * xmlFuzzDataFree:
167 *
168 * Cleanup fuzz data provider.
169 */
170void
171xmlFuzzDataCleanup(void) {
172 xmlFree(fuzzData.outBuf);
173 xmlHashFree(fuzzData.entities, xmlHashDefaultDeallocator);
174}
175
176/**
177 * xmlFuzzWriteInt:
178 * @out: output file
179 * @v: integer to write
180 * @size: size of integer in bytes
181 *
182 * Write an integer to the fuzz data.
183 */
184void
185xmlFuzzWriteInt(FILE *out, size_t v, int size) {
186 int shift;
187
188 while (size > (int) sizeof(size_t)) {
189 putc(0, out);
190 size--;
191 }
192
193 shift = size * 8;
194 while (shift > 0) {
195 shift -= 8;
196 putc((v >> shift) & 255, out);
197 }
198}
199
200/**
201 * xmlFuzzReadInt:
202 * @size: size of integer in bytes
203 *
204 * Read an integer from the fuzz data.
205 */
206size_t
207xmlFuzzReadInt(int size) {
208 size_t ret = 0;
209
210 while ((size > 0) && (fuzzData.remaining > 0)) {
211 unsigned char c = (unsigned char) *fuzzData.ptr++;
212 fuzzData.remaining--;
213 ret = (ret << 8) | c;
214 size--;
215 }
216
217 return ret;
218}
219
220/**
221 * xmlFuzzBytesRemaining:
222 *
223 * Return number of remaining bytes in fuzz data.
224 */
225size_t
226xmlFuzzBytesRemaining(void) {
227 return(fuzzData.remaining);
228}
229
230/**
231 * xmlFuzzReadRemaining:
232 * @size: size of string in bytes
233 *
234 * Read remaining bytes from fuzz data.
235 */
236const char *
237xmlFuzzReadRemaining(size_t *size) {
238 const char *ret = fuzzData.ptr;
239
240 *size = fuzzData.remaining;
241 fuzzData.ptr += fuzzData.remaining;
242 fuzzData.remaining = 0;
243
244 return(ret);
245}
246
247/*
248 * xmlFuzzWriteString:
249 * @out: output file
250 * @str: string to write
251 *
252 * Write a random-length string to file in a format similar to
253 * FuzzedDataProvider. Backslash followed by newline marks the end of the
254 * string. Two backslashes are used to escape a backslash.
255 */
256void
257xmlFuzzWriteString(FILE *out, const char *str) {
258 for (; *str; str++) {
259 int c = (unsigned char) *str;
260 putc(c, out);
261 if (c == '\\')
262 putc(c, out);
263 }
264 putc('\\', out);
265 putc('\n', out);
266}
267
268/**
269 * xmlFuzzReadString:
270 * @size: size of string in bytes
271 *
272 * Read a random-length string from the fuzz data.
273 *
274 * The format is similar to libFuzzer's FuzzedDataProvider but treats
275 * backslash followed by newline as end of string. This makes the fuzz data
276 * more readable. A backslash character is escaped with another backslash.
277 *
278 * Returns a zero-terminated string or NULL if the fuzz data is exhausted.
279 */
280const char *
281xmlFuzzReadString(size_t *size) {
282 const char *out = fuzzData.outPtr;
283
284 while (fuzzData.remaining > 0) {
285 int c = *fuzzData.ptr++;
286 fuzzData.remaining--;
287
288 if ((c == '\\') && (fuzzData.remaining > 0)) {
289 int c2 = *fuzzData.ptr;
290
291 if (c2 == '\n') {
292 fuzzData.ptr++;
293 fuzzData.remaining--;
294 if (size != NULL)
295 *size = fuzzData.outPtr - out;
296 *fuzzData.outPtr++ = '\0';
297 return(out);
298 }
299 if (c2 == '\\') {
300 fuzzData.ptr++;
301 fuzzData.remaining--;
302 }
303 }
304
305 *fuzzData.outPtr++ = c;
306 }
307
308 if (fuzzData.outPtr > out) {
309 if (size != NULL)
310 *size = fuzzData.outPtr - out;
311 *fuzzData.outPtr++ = '\0';
312 return(out);
313 }
314
315 if (size != NULL)
316 *size = 0;
317 return(NULL);
318}
319
320/**
321 * xmlFuzzReadEntities:
322 *
323 * Read entities like the main XML file, external DTDs, external parsed
324 * entities from fuzz data.
325 */
326void
327xmlFuzzReadEntities(void) {
328 size_t num = 0;
329
330 while (1) {
331 const char *url, *entity;
332 size_t urlSize, entitySize;
333 xmlFuzzEntityInfo *entityInfo;
334
335 url = xmlFuzzReadString(&urlSize);
336 if (url == NULL) break;
337
338 entity = xmlFuzzReadString(&entitySize);
339 if (entity == NULL) break;
340
341 /*
342 * Cap URL size to avoid quadratic behavior when generating
343 * error messages or looking up entities.
344 */
345 if (urlSize < 50 &&
346 xmlHashLookup(fuzzData.entities, (xmlChar *)url) == NULL) {
347 entityInfo = xmlMalloc(sizeof(xmlFuzzEntityInfo));
348 if (entityInfo == NULL)
349 break;
350 entityInfo->data = entity;
351 entityInfo->size = entitySize;
352
353 xmlHashAddEntry(fuzzData.entities, (xmlChar *)url, entityInfo);
354
355 if (num == 0) {
356 fuzzData.mainUrl = url;
357 fuzzData.mainEntity = entityInfo;
358 }
359
360 num++;
361 }
362 }
363}
364
365/**
366 * xmlFuzzMainUrl:
367 *
368 * Returns the main URL.
369 */
370const char *
371xmlFuzzMainUrl(void) {
372 return(fuzzData.mainUrl);
373}
374
375/**
376 * xmlFuzzMainEntity:
377 * @size: size of the main entity in bytes
378 *
379 * Returns the main entity.
380 */
381const char *
382xmlFuzzMainEntity(size_t *size) {
383 if (fuzzData.mainEntity == NULL)
384 return(NULL);
385 *size = fuzzData.mainEntity->size;
386 return(fuzzData.mainEntity->data);
387}
388
389/**
390 * xmlFuzzEntityLoader:
391 *
392 * The entity loader for fuzz data.
393 */
394xmlParserInputPtr
395xmlFuzzEntityLoader(const char *URL, const char *ID ATTRIBUTE_UNUSED,
396 xmlParserCtxtPtr ctxt) {
397 xmlParserInputPtr input;
398 xmlFuzzEntityInfo *entity;
399
400 if (URL == NULL)
401 return(NULL);
402 entity = xmlHashLookup(fuzzData.entities, (xmlChar *) URL);
403 if (entity == NULL)
404 return(NULL);
405
406 input = xmlNewInputStream(ctxt);
407 if (input == NULL)
408 return(NULL);
409 input->filename = (char *) xmlCharStrdup(URL);
410 if (input->filename == NULL) {
411 xmlCtxtErrMemory(ctxt);
412 xmlFreeInputStream(input);
413 return(NULL);
414 }
415 input->buf = xmlParserInputBufferCreateMem(entity->data, entity->size,
416 XML_CHAR_ENCODING_NONE);
417 if (input->buf == NULL) {
418 xmlCtxtErrMemory(ctxt);
419 xmlFreeInputStream(input);
420 return(NULL);
421 }
422 input->base = input->cur = xmlBufContent(input->buf->buffer);
423 input->end = input->base + xmlBufUse(input->buf->buffer);
424
425 return input;
426}
427
428char *
429xmlSlurpFile(const char *path, size_t *sizeRet) {
430 FILE *file;
431 struct stat statbuf;
432 char *data;
433 size_t size;
434
435 if ((stat(path, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode)))
436 return(NULL);
437 size = statbuf.st_size;
438 file = fopen(path, "rb");
439 if (file == NULL)
440 return(NULL);
441 data = xmlMalloc(size + 1);
442 if (data != NULL) {
443 if (fread(data, 1, size, file) != size) {
444 xmlFree(data);
445 data = NULL;
446 } else {
447 data[size] = 0;
448 if (sizeRet != NULL)
449 *sizeRet = size;
450 }
451 }
452 fclose(file);
453
454 return(data);
455}
456
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette