|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <fcntl.h> |
|
|
#include <stdlib.h> |
|
|
#include <stdio.h> |
|
|
#include <unistd.h> |
|
|
|
|
|
#include <libxml/catalog.h> |
|
|
#include <libxml/parser.h> |
|
|
#include <libxml/xmlerror.h> |
|
|
#include <libxml/xmlmemory.h> |
|
|
|
|
|
#include "private/lint.h" |
|
|
|
|
|
#include "fuzz.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const char *const switches[] = { |
|
|
"--auto", |
|
|
"--c14n", |
|
|
"--c14n11", |
|
|
"--compress", |
|
|
"--copy", |
|
|
"--debug", |
|
|
NULL, |
|
|
"--dropdtd", |
|
|
"--dtdattr", |
|
|
"--exc-c14n", |
|
|
"--format", |
|
|
NULL, |
|
|
"--huge", |
|
|
"--insert", |
|
|
"--loaddtd", |
|
|
"--load-trace", |
|
|
NULL, |
|
|
"--noblanks", |
|
|
"--nocdata", |
|
|
"--nocompact", |
|
|
"--nodefdtd", |
|
|
"--nodict", |
|
|
"--noenc", |
|
|
"--noent", |
|
|
"--nofixup-base-uris", |
|
|
"--nonet", |
|
|
"--noout", |
|
|
"--nowarning", |
|
|
NULL, |
|
|
"--noxincludenode", |
|
|
"--nsclean", |
|
|
"--oldxml10", |
|
|
"--pedantic", |
|
|
"--postvalid", |
|
|
"--push", |
|
|
"--pushsmall", |
|
|
"--quiet", |
|
|
"--recover", |
|
|
"--repeat", |
|
|
"--sax1", |
|
|
NULL, |
|
|
"--timing", |
|
|
"--valid", |
|
|
"--version", |
|
|
"--walker", |
|
|
"--xinclude", |
|
|
"--xmlout" |
|
|
}; |
|
|
static const size_t numSwitches = sizeof(switches) / sizeof(switches[0]); |
|
|
|
|
|
struct { |
|
|
const char **argv; |
|
|
size_t argi; |
|
|
} vars; |
|
|
|
|
|
static void |
|
|
pushArg(const char *str) { |
|
|
vars.argv[vars.argi++] = str; |
|
|
} |
|
|
|
|
|
int |
|
|
LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED, |
|
|
char ***argv ATTRIBUTE_UNUSED) { |
|
|
int fd; |
|
|
|
|
|
|
|
|
fd = open("/dev/null", O_WRONLY); |
|
|
if (fd == -1) { |
|
|
perror("/dev/null"); |
|
|
abort(); |
|
|
} |
|
|
if (dup2(fd, STDOUT_FILENO) == -1) { |
|
|
perror("dup2"); |
|
|
abort(); |
|
|
} |
|
|
close(fd); |
|
|
|
|
|
return 0; |
|
|
} |
|
|
|
|
|
int |
|
|
LLVMFuzzerTestOneInput(const char *data, size_t size) { |
|
|
char maxmemBuf[20]; |
|
|
char maxAmplBuf[20]; |
|
|
char prettyBuf[20]; |
|
|
const char *sval, *docBuffer, *docUrl; |
|
|
size_t ssize, docSize, i; |
|
|
unsigned uval; |
|
|
int ival; |
|
|
|
|
|
if (xmlMemUsed() != 0) { |
|
|
fprintf(stderr, "Undetected leak in previous iteration\n"); |
|
|
abort(); |
|
|
} |
|
|
|
|
|
vars.argv = malloc((numSwitches + 5 + 6 * 2) * sizeof(vars.argv[0])); |
|
|
vars.argi = 0; |
|
|
pushArg("xmllint"), |
|
|
pushArg("--nocatalogs"); |
|
|
|
|
|
xmlFuzzDataInit(data, size); |
|
|
|
|
|
for (i = 0; i < numSwitches; i++) { |
|
|
if (i % 32 == 0) |
|
|
uval = xmlFuzzReadInt(4); |
|
|
if ((uval & 1) && (switches[i] != NULL)) |
|
|
pushArg(switches[i]); |
|
|
uval >>= 1; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (uval & 3) { |
|
|
case 0: |
|
|
|
|
|
break; |
|
|
case 1: |
|
|
|
|
|
pushArg("--html"); |
|
|
break; |
|
|
case 2: |
|
|
|
|
|
pushArg("--stream"); |
|
|
break; |
|
|
case 3: |
|
|
|
|
|
pushArg("--sax"); |
|
|
break; |
|
|
} |
|
|
|
|
|
uval = xmlFuzzReadInt(4); |
|
|
if (uval > 0) { |
|
|
if (size <= (INT_MAX - 2000) / 20) |
|
|
uval %= size * 20 + 2000; |
|
|
else |
|
|
uval %= INT_MAX; |
|
|
snprintf(maxmemBuf, 20, "%u", uval); |
|
|
pushArg("--maxmem"); |
|
|
pushArg(maxmemBuf); |
|
|
} |
|
|
|
|
|
ival = xmlFuzzReadInt(1); |
|
|
if (ival >= 1 && ival <= 5) { |
|
|
snprintf(maxAmplBuf, 20, "%d", ival); |
|
|
pushArg("--max-ampl"); |
|
|
pushArg(maxAmplBuf); |
|
|
} |
|
|
|
|
|
ival = xmlFuzzReadInt(1); |
|
|
if (ival != 0) { |
|
|
snprintf(prettyBuf, 20, "%d", ival % 4); |
|
|
pushArg("--pretty"); |
|
|
pushArg(prettyBuf); |
|
|
} |
|
|
|
|
|
sval = xmlFuzzReadString(&ssize); |
|
|
if (ssize > 0) { |
|
|
pushArg("--encode"); |
|
|
pushArg(sval); |
|
|
} |
|
|
|
|
|
sval = xmlFuzzReadString(&ssize); |
|
|
if (ssize > 0) { |
|
|
pushArg("--pattern"); |
|
|
pushArg(sval); |
|
|
} |
|
|
|
|
|
sval = xmlFuzzReadString(&ssize); |
|
|
if (ssize > 0) { |
|
|
pushArg("--xpath"); |
|
|
pushArg(sval); |
|
|
} |
|
|
|
|
|
xmlFuzzReadEntities(); |
|
|
docBuffer = xmlFuzzMainEntity(&docSize); |
|
|
docUrl = xmlFuzzMainUrl(); |
|
|
if (docBuffer == NULL || docUrl[0] == '-') |
|
|
goto exit; |
|
|
pushArg(docUrl); |
|
|
|
|
|
pushArg(NULL); |
|
|
|
|
|
xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc); |
|
|
#ifdef LIBXML_CATALOG_ENABLED |
|
|
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE); |
|
|
#endif |
|
|
|
|
|
xmllintMain(vars.argi - 1, vars.argv, stdout, xmlFuzzResourceLoader); |
|
|
|
|
|
xmlMemSetup(free, malloc, realloc, xmlMemStrdup); |
|
|
|
|
|
exit: |
|
|
xmlFuzzDataCleanup(); |
|
|
free(vars.argv); |
|
|
return(0); |
|
|
} |
|
|
|
|
|
size_t |
|
|
LLVMFuzzerCustomMutator(char *data, size_t size, size_t maxSize, |
|
|
unsigned seed) { |
|
|
static const xmlFuzzChunkDesc chunks[] = { |
|
|
{ 8, XML_FUZZ_PROB_ONE / 10 }, |
|
|
{ 4, XML_FUZZ_PROB_ONE / 10 }, |
|
|
{ 1, XML_FUZZ_PROB_ONE / 100 }, |
|
|
{ 1, XML_FUZZ_PROB_ONE / 100 }, |
|
|
{ 0, 0 } |
|
|
}; |
|
|
|
|
|
return xmlFuzzMutateChunks(chunks, data, size, maxSize, seed, |
|
|
LLVMFuzzerMutate); |
|
|
} |
|
|
|
|
|
|