[libxml2]Add libxml2 library

This commit is contained in:
zhoujiale
2026-07-26 16:57:28 +08:00
committed by zhoujiale
parent 0a44ec8a06
commit e841ac915d
3790 changed files with 668244 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
api
corpus/
genSeed
html
lint
reader
regexp
schema
seed/
testFuzzer
uri
valid
xinclude
xml
xpath
+239
View File
@@ -0,0 +1,239 @@
AUTOMAKE_OPTIONS = -Wno-syntax
EXTRA_PROGRAMS = genSeed \
api html lint reader regexp schema uri valid xinclude \
xml xpath
check_PROGRAMS = testFuzzer
EXTRA_DIST = html.dict regexp.dict schema.dict xml.dict xpath.dict \
static_seed/uri static_seed/regexp fuzz.h
CLEANFILES = $(EXTRA_PROGRAMS)
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
DEPENDENCIES = $(top_builddir)/libxml2.la
LDADD = $(top_builddir)/libxml2.la
XML_MAX_LEN = 80000
# Single quotes to avoid wildcard expansion by the shell
XML_SEED_CORPUS_SRC = \
'$(top_srcdir)/test/*' \
'$(top_srcdir)/test/errors/*.xml' \
'$(top_srcdir)/test/errors10/*.xml' \
'$(top_srcdir)/test/namespaces/*' \
'$(top_srcdir)/test/recurse/*.xml' \
'$(top_srcdir)/test/SVG/*.xml' \
'$(top_srcdir)/test/valid/*.xml' \
'$(top_srcdir)/test/VC/*' \
'$(top_srcdir)/test/VCM/*' \
'$(top_srcdir)/test/XInclude/docs/*' \
'$(top_srcdir)/test/XInclude/without-reader/*' \
'$(top_srcdir)/test/xmlid/*'
testFuzzer_SOURCES = testFuzzer.c fuzz.c
.PHONY: corpus clean-corpus
corpus: seed/html.stamp seed/lint.stamp seed/reader.stamp seed/regexp.stamp \
seed/schema.stamp seed/uri.stamp seed/valid.stamp seed/xinclude.stamp \
seed/xml.stamp seed/xpath.stamp
check-local: corpus
./testFuzzer$(EXEEXT)
clean-corpus:
rm -rf seed
clean-local: clean-corpus
# Seed corpus
genSeed_SOURCES = genSeed.c fuzz.c
# XML fuzzer
seed/xml.stamp: genSeed$(EXEEXT)
@mkdir -p seed/xml
./genSeed$(EXEEXT) xml $(XML_SEED_CORPUS_SRC)
@touch seed/xml.stamp
xml_SOURCES = xml.c fuzz.c
xml_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer
fuzz-xml: xml$(EXEEXT) seed/xml.stamp
@mkdir -p corpus/xml
./xml$(EXEEXT) \
-dict=$(srcdir)/xml.dict \
-max_len=$(XML_MAX_LEN) \
$$XML_FUZZ_OPTIONS \
corpus/xml seed/xml
# DTD validation fuzzer
seed/valid.stamp: genSeed$(EXEEXT)
@mkdir -p seed/valid
./genSeed$(EXEEXT) valid $(XML_SEED_CORPUS_SRC)
@touch seed/valid.stamp
valid_SOURCES = valid.c fuzz.c
valid_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer
fuzz-valid: valid$(EXEEXT) seed/valid.stamp
@mkdir -p corpus/valid
./valid$(EXEEXT) \
-dict=$(srcdir)/xml.dict \
-max_len=$(XML_MAX_LEN) \
$$XML_FUZZ_OPTIONS \
corpus/valid seed/valid
# XInclude fuzzer
seed/xinclude.stamp: genSeed$(EXEEXT)
@mkdir -p seed/xinclude
./genSeed$(EXEEXT) xinclude $(XML_SEED_CORPUS_SRC)
@touch seed/xinclude.stamp
xinclude_SOURCES = xinclude.c fuzz.c
xinclude_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer
fuzz-xinclude: xinclude$(EXEEXT) seed/xinclude.stamp
@mkdir -p corpus/xinclude
./xinclude$(EXEEXT) \
-dict=$(srcdir)/xml.dict \
-max_len=$(XML_MAX_LEN) \
$$XML_FUZZ_OPTIONS \
corpus/xinclude seed/xinclude
# HTML fuzzer
seed/html.stamp: genSeed$(EXEEXT)
@mkdir -p seed/html
./genSeed$(EXEEXT) html '$(top_srcdir)/test/HTML/*'
@touch seed/html.stamp
html_SOURCES = html.c fuzz.c
html_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer
fuzz-html: html$(EXEEXT) seed/html.stamp
@mkdir -p corpus/html
./html$(EXEEXT) \
-dict=$(srcdir)/html.dict \
-max_len=1000000 \
$$XML_FUZZ_OPTIONS \
corpus/html seed/html
# Reader fuzzer
seed/reader.stamp: genSeed$(EXEEXT)
@mkdir -p seed/reader
./genSeed$(EXEEXT) reader $(XML_SEED_CORPUS_SRC)
@touch seed/reader.stamp
reader_SOURCES = reader.c fuzz.c
reader_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer
fuzz-reader: reader$(EXEEXT) seed/reader.stamp
@mkdir -p corpus/reader
./reader$(EXEEXT) \
-dict=$(srcdir)/xml.dict \
-max_len=$(XML_MAX_LEN) \
$$XML_FUZZ_OPTIONS \
corpus/reader seed/reader
# xmllint fuzzer
seed/lint.stamp: genSeed$(EXEEXT)
@mkdir -p seed/lint
./genSeed$(EXEEXT) lint $(XML_SEED_CORPUS_SRC)
@touch seed/lint.stamp
lint_SOURCES = lint.c fuzz.c ../xmllint.c ../shell.c
lint_LDFLAGS = -fsanitize=fuzzer
fuzz-lint: lint$(EXEEXT) seed/lint.stamp
@mkdir -p corpus/lint
./lint$(EXEEXT) \
-dict=$(srcdir)/xml.dict \
-max_len=$(XML_MAX_LEN) \
$$XML_FUZZ_OPTIONS \
corpus/lint seed/lint
# API fuzzer
api_SOURCES = api.c fuzz.c
api_LDFLAGS = -fsanitize=fuzzer
fuzz-api: api$(EXEEXT)
@mkdir -p corpus/api
./api$(EXEEXT) \
-max_len=100 \
$$XML_FUZZ_OPTIONS \
corpus/api
# Regexp fuzzer
seed/regexp.stamp:
@mkdir -p seed/regexp
cp -r $(srcdir)/static_seed/regexp seed
@touch seed/regexp.stamp
regexp_SOURCES = regexp.c fuzz.c
regexp_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer
fuzz-regexp: regexp$(EXEEXT) seed/regexp.stamp
@mkdir -p corpus/regexp
./regexp$(EXEEXT) \
-dict=$(srcdir)/regexp.dict \
-max_len=200 \
$$XML_FUZZ_OPTIONS \
corpus/regexp seed/regexp
# URI fuzzer
seed/uri.stamp:
@mkdir -p seed/uri
cp -r $(srcdir)/static_seed/uri seed
@touch seed/uri.stamp
uri_SOURCES = uri.c fuzz.c
uri_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer
fuzz-uri: uri$(EXEEXT) seed/uri.stamp
@mkdir -p corpus/uri
./uri$(EXEEXT) \
-max_len=10000 \
$$XML_FUZZ_OPTIONS \
corpus/uri seed/uri
# XML Schema fuzzer
seed/schema.stamp: genSeed$(EXEEXT)
@mkdir -p seed/schema
./genSeed$(EXEEXT) schema '$(top_srcdir)/test/schemas/*.xsd'
@touch seed/schema.stamp
schema_SOURCES = schema.c fuzz.c
schema_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer
fuzz-schema: schema$(EXEEXT) seed/schema.stamp
@mkdir -p corpus/schema
./schema$(EXEEXT) \
-dict=$(srcdir)/schema.dict \
-max_len=$(XML_MAX_LEN) \
$$XML_FUZZ_OPTIONS \
corpus/schema seed/schema
# XPath fuzzer
seed/xpath.stamp: genSeed$(EXEEXT)
@mkdir -p seed/xpath
./genSeed$(EXEEXT) xpath '$(top_srcdir)/test/XPath'
@touch seed/xpath.stamp
xpath_SOURCES = xpath.c fuzz.c
xpath_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer
fuzz-xpath: xpath$(EXEEXT) seed/xpath.stamp
@mkdir -p corpus/xpath
./xpath$(EXEEXT) \
-dict=$(srcdir)/xpath.dict \
-max_len=10000 \
$$XML_FUZZ_OPTIONS \
corpus/xpath seed/xpath
+57
View File
@@ -0,0 +1,57 @@
libFuzzer instructions for libxml2
==================================
Set compiler and options. Make sure to enable at least basic optimizations
to avoid excessive stack usage. Also enable some debug output to get
meaningful stack traces.
export CC=clang
export CFLAGS=" \
-O1 -gline-tables-only \
-fsanitize=fuzzer-no-link,address,undefined \
-fno-sanitize-recover=all \
-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION"
Since llvm-symbolizer can use libxml2 itself, you may need the following
wrapper to make sure that it doesn't use the instrumented version of
libxml2:
export ASAN_SYMBOLIZER_PATH="$(pwd)/.gitlab-ci/llvm-symbolizer"
Other options that can improve stack traces:
-fno-omit-frame-pointer
-fno-inline
-fno-optimize-sibling-calls (disables tail call optimization)
Build libxml2 with instrumentation:
./configure --without-python
make
Run fuzzers:
make -C fuzz fuzz-xml
The environment variable XML_FUZZ_OPTIONS can be used to pass additional
flags to the fuzzer.
Malloc failure injection
------------------------
Most fuzzers inject malloc failures to cover code paths handling these
errors. This can lead to surprises when debugging crashes. You can set
the macro XML_FUZZ_MALLOC_ABORT in fuzz/fuzz.c to make the fuzz target
abort at the malloc invocation which would fail. This tells you if
and where a malloc failure was injected.
Some fuzzers also test whether malloc failures are reported. To debug
failures which aren't reported, it's helpful to enable
XML_FUZZ_MALLOC_ABORT to see which allocation failed. Debugging
failures which are erroneously reported can be harder. If the report
goes through xmlRaiseMemoryError, you can abort() there to get a
stack trace.
Bugs related to handling of malloc failures are not considered
security-critical by the libxml2 maintainers. Nevertheless, we'd like
to see such issues reported.
+3614
View File
File diff suppressed because it is too large Load Diff
+603
View File
@@ -0,0 +1,603 @@
/*
* fuzz.c: Common functions for fuzzing.
*
* See Copyright for the status of this software.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <libxml/hash.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#include <libxml/tree.h>
#include <libxml/xmlIO.h>
#include "fuzz.h"
typedef struct {
const char *data;
size_t size;
} xmlFuzzEntityInfo;
/* Single static instance for now */
static struct {
/* Original data */
const char *data;
size_t size;
/* Remaining data */
const char *ptr;
size_t remaining;
/* Buffer for unescaped strings */
char *outBuf;
char *outPtr; /* Free space at end of buffer */
xmlHashTablePtr entities; /* Maps URLs to xmlFuzzEntityInfos */
/* The first entity is the main entity. */
const char *mainUrl;
xmlFuzzEntityInfo *mainEntity;
const char *secondaryUrl;
xmlFuzzEntityInfo *secondaryEntity;
} fuzzData;
size_t fuzzNumAttempts;
size_t fuzzFailurePos;
int fuzzAllocFailed;
int fuzzIoFailed;
/**
* xmlFuzzErrorFunc:
*
* An error function that simply discards all errors.
*/
void
xmlFuzzErrorFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg ATTRIBUTE_UNUSED,
...) {
}
/**
* xmlFuzzSErrorFunc:
*
* A structured error function that simply discards all errors.
*/
void
xmlFuzzSErrorFunc(void *ctx ATTRIBUTE_UNUSED,
const xmlError *error ATTRIBUTE_UNUSED) {
}
/*
* Failure injection.
*
* To debug issues involving injected failures, it's often helpful to set
* FAILURE_ABORT to 1. This should provide a backtrace of the failed
* operation.
*/
#define XML_FUZZ_FAILURE_ABORT 0
void
xmlFuzzInjectFailure(size_t failurePos) {
fuzzNumAttempts = 0;
fuzzFailurePos = failurePos;
fuzzAllocFailed = 0;
fuzzIoFailed = 0;
}
static int
xmlFuzzTryMalloc(void) {
if (fuzzFailurePos > 0) {
fuzzNumAttempts += 1;
if (fuzzNumAttempts == fuzzFailurePos) {
#if XML_FUZZ_FAILURE_ABORT
abort();
#endif
fuzzAllocFailed = 1;
return -1;
}
}
return 0;
}
static int
xmlFuzzTryIo(void) {
if (fuzzFailurePos > 0) {
fuzzNumAttempts += 1;
if (fuzzNumAttempts == fuzzFailurePos) {
#if XML_FUZZ_FAILURE_ABORT
abort();
#endif
fuzzIoFailed = 1;
return -1;
}
}
return 0;
}
static void *
xmlFuzzMalloc(size_t size) {
void *ret;
if (xmlFuzzTryMalloc() < 0)
return NULL;
ret = malloc(size);
if (ret == NULL)
fuzzAllocFailed = 1;
return ret;
}
static void *
xmlFuzzRealloc(void *ptr, size_t size) {
void *ret;
if (xmlFuzzTryMalloc() < 0)
return NULL;
ret = realloc(ptr, size);
if (ret == NULL)
fuzzAllocFailed = 1;
return ret;
}
void
xmlFuzzMemSetup(void) {
xmlMemSetup(free, xmlFuzzMalloc, xmlFuzzRealloc, xmlMemStrdup);
}
int
xmlFuzzMallocFailed(void) {
return fuzzAllocFailed;
}
void
xmlFuzzResetFailure(void) {
fuzzAllocFailed = 0;
fuzzIoFailed = 0;
}
void
xmlFuzzCheckFailureReport(const char *func, int oomReport, int ioReport) {
if (oomReport >= 0 && fuzzAllocFailed != oomReport) {
fprintf(stderr, "%s: malloc failure %s reported\n",
func, fuzzAllocFailed ? "not" : "erroneously");
abort();
}
if (ioReport >= 0 && fuzzIoFailed != ioReport) {
fprintf(stderr, "%s: IO failure %s reported\n",
func, fuzzIoFailed ? "not" : "erroneously");
abort();
}
fuzzAllocFailed = 0;
fuzzIoFailed = 0;
}
/**
* xmlFuzzDataInit:
*
* Initialize fuzz data provider.
*/
void
xmlFuzzDataInit(const char *data, size_t size) {
fuzzData.data = data;
fuzzData.size = size;
fuzzData.ptr = data;
fuzzData.remaining = size;
fuzzData.outBuf = xmlMalloc(size + 1);
fuzzData.outPtr = fuzzData.outBuf;
fuzzData.entities = xmlHashCreate(8);
fuzzData.mainUrl = NULL;
fuzzData.mainEntity = NULL;
fuzzData.secondaryUrl = NULL;
fuzzData.secondaryEntity = NULL;
}
/**
* xmlFuzzDataFree:
*
* Cleanup fuzz data provider.
*/
void
xmlFuzzDataCleanup(void) {
xmlFree(fuzzData.outBuf);
xmlHashFree(fuzzData.entities, xmlHashDefaultDeallocator);
}
/**
* xmlFuzzWriteInt:
* @out: output file
* @v: integer to write
* @size: size of integer in bytes
*
* Write an integer to the fuzz data.
*/
void
xmlFuzzWriteInt(FILE *out, size_t v, int size) {
int shift;
while (size > (int) sizeof(size_t)) {
putc(0, out);
size--;
}
shift = size * 8;
while (shift > 0) {
shift -= 8;
putc((v >> shift) & 255, out);
}
}
/**
* xmlFuzzReadInt:
* @size: size of integer in bytes
*
* Read an integer from the fuzz data.
*/
size_t
xmlFuzzReadInt(int size) {
size_t ret = 0;
while ((size > 0) && (fuzzData.remaining > 0)) {
unsigned char c = (unsigned char) *fuzzData.ptr++;
fuzzData.remaining--;
ret = (ret << 8) | c;
size--;
}
return ret;
}
/**
* xmlFuzzBytesRemaining:
*
* Return number of remaining bytes in fuzz data.
*/
size_t
xmlFuzzBytesRemaining(void) {
return(fuzzData.remaining);
}
/**
* xmlFuzzReadRemaining:
* @size: size of string in bytes
*
* Read remaining bytes from fuzz data.
*/
const char *
xmlFuzzReadRemaining(size_t *size) {
const char *ret = fuzzData.ptr;
*size = fuzzData.remaining;
fuzzData.ptr += fuzzData.remaining;
fuzzData.remaining = 0;
return(ret);
}
/*
* xmlFuzzWriteString:
* @out: output file
* @str: string to write
*
* Write a random-length string to file in a format similar to
* FuzzedDataProvider. Backslash followed by newline marks the end of the
* string. Two backslashes are used to escape a backslash.
*/
void
xmlFuzzWriteString(FILE *out, const char *str) {
for (; *str; str++) {
int c = (unsigned char) *str;
putc(c, out);
if (c == '\\')
putc(c, out);
}
putc('\\', out);
putc('\n', out);
}
/**
* xmlFuzzReadString:
* @size: size of string in bytes
*
* Read a random-length string from the fuzz data.
*
* The format is similar to libFuzzer's FuzzedDataProvider but treats
* backslash followed by newline as end of string. This makes the fuzz data
* more readable. A backslash character is escaped with another backslash.
*
* Returns a zero-terminated string or NULL if the fuzz data is exhausted.
*/
const char *
xmlFuzzReadString(size_t *size) {
const char *out = fuzzData.outPtr;
while (fuzzData.remaining > 0) {
int c = *fuzzData.ptr++;
fuzzData.remaining--;
if ((c == '\\') && (fuzzData.remaining > 0)) {
int c2 = *fuzzData.ptr;
if (c2 == '\n') {
fuzzData.ptr++;
fuzzData.remaining--;
if (size != NULL)
*size = fuzzData.outPtr - out;
*fuzzData.outPtr++ = '\0';
return(out);
}
if (c2 == '\\') {
fuzzData.ptr++;
fuzzData.remaining--;
}
}
*fuzzData.outPtr++ = c;
}
if (fuzzData.outPtr > out) {
if (size != NULL)
*size = fuzzData.outPtr - out;
*fuzzData.outPtr++ = '\0';
return(out);
}
if (size != NULL)
*size = 0;
return(NULL);
}
/**
* xmlFuzzReadEntities:
*
* Read entities like the main XML file, external DTDs, external parsed
* entities from fuzz data.
*/
void
xmlFuzzReadEntities(void) {
size_t num = 0;
while (1) {
const char *url, *entity;
size_t urlSize, entitySize;
xmlFuzzEntityInfo *entityInfo;
url = xmlFuzzReadString(&urlSize);
if (url == NULL) break;
entity = xmlFuzzReadString(&entitySize);
if (entity == NULL) break;
/*
* Cap URL size to avoid quadratic behavior when generating
* error messages or looking up entities.
*/
if (urlSize < 50 &&
xmlHashLookup(fuzzData.entities, (xmlChar *)url) == NULL) {
entityInfo = xmlMalloc(sizeof(xmlFuzzEntityInfo));
if (entityInfo == NULL)
break;
entityInfo->data = entity;
entityInfo->size = entitySize;
xmlHashAddEntry(fuzzData.entities, (xmlChar *)url, entityInfo);
if (num == 0) {
fuzzData.mainUrl = url;
fuzzData.mainEntity = entityInfo;
} else if (num == 1) {
fuzzData.secondaryUrl = url;
fuzzData.secondaryEntity = entityInfo;
}
num++;
}
}
}
/**
* xmlFuzzMainUrl:
*
* Returns the main URL.
*/
const char *
xmlFuzzMainUrl(void) {
return(fuzzData.mainUrl);
}
/**
* xmlFuzzMainEntity:
* @size: size of the main entity in bytes
*
* Returns the main entity.
*/
const char *
xmlFuzzMainEntity(size_t *size) {
if (fuzzData.mainEntity == NULL)
return(NULL);
*size = fuzzData.mainEntity->size;
return(fuzzData.mainEntity->data);
}
/**
* xmlFuzzSecondaryUrl:
*
* Returns the secondary URL.
*/
const char *
xmlFuzzSecondaryUrl(void) {
return(fuzzData.secondaryUrl);
}
/**
* xmlFuzzSecondaryEntity:
* @size: size of the secondary entity in bytes
*
* Returns the secondary entity.
*/
const char *
xmlFuzzSecondaryEntity(size_t *size) {
if (fuzzData.secondaryEntity == NULL)
return(NULL);
*size = fuzzData.secondaryEntity->size;
return(fuzzData.secondaryEntity->data);
}
/**
* xmlFuzzResourceLoader:
*
* The resource loader for fuzz data.
*/
xmlParserErrors
xmlFuzzResourceLoader(void *data ATTRIBUTE_UNUSED, const char *URL,
const char *ID ATTRIBUTE_UNUSED,
xmlResourceType type ATTRIBUTE_UNUSED,
xmlParserInputFlags flags ATTRIBUTE_UNUSED,
xmlParserInputPtr *out) {
xmlParserInputPtr input;
xmlFuzzEntityInfo *entity;
entity = xmlHashLookup(fuzzData.entities, (xmlChar *) URL);
if (entity == NULL)
return(XML_IO_ENOENT);
/* IO failure injection */
if (xmlFuzzTryIo() < 0)
return(XML_IO_EIO);
input = xmlNewInputFromMemory(URL, entity->data, entity->size,
XML_INPUT_BUF_STATIC |
XML_INPUT_BUF_ZERO_TERMINATED);
if (input == NULL)
return(XML_ERR_NO_MEMORY);
*out = input;
return(XML_ERR_OK);
}
char *
xmlSlurpFile(const char *path, size_t *sizeRet) {
FILE *file;
struct stat statbuf;
char *data;
size_t size;
if ((stat(path, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode)))
return(NULL);
size = statbuf.st_size;
file = fopen(path, "rb");
if (file == NULL)
return(NULL);
data = xmlMalloc(size + 1);
if (data != NULL) {
if (fread(data, 1, size, file) != size) {
xmlFree(data);
data = NULL;
} else {
data[size] = 0;
if (sizeRet != NULL)
*sizeRet = size;
}
}
fclose(file);
return(data);
}
int
xmlFuzzOutputWrite(void *ctxt ATTRIBUTE_UNUSED,
const char *buffer ATTRIBUTE_UNUSED, int len) {
if (xmlFuzzTryIo() < 0)
return -XML_IO_EIO;
return len;
}
int
xmlFuzzOutputClose(void *ctxt ATTRIBUTE_UNUSED) {
if (xmlFuzzTryIo() < 0)
return XML_IO_EIO;
return 0;
}
/**
* xmlFuzzMutateChunks:
* @chunks: array of chunk descriptions
* @data: fuzz data (from LLVMFuzzerCustomMutator)
* @size: data size (from LLVMFuzzerCustomMutator)
* @maxSize: max data size (from LLVMFuzzerCustomMutator)
* @seed: seed (from LLVMFuzzerCustomMutator)
* @mutator: mutator function, use LLVMFuzzerMutate
*
* Mutates one of several chunks with a given probability.
*
* Probability is a value between 0 and XML_FUZZ_PROB_ONE.
*
* The last chunk has flexible size and must have size and
* mutateProb set to 0.
*
* Returns the size of the mutated data like LLVMFuzzerCustomMutator.
*/
size_t
xmlFuzzMutateChunks(const xmlFuzzChunkDesc *chunks,
char *data, size_t size, size_t maxSize, unsigned seed,
xmlFuzzMutator mutator) {
size_t off = 0;
size_t ret, chunkSize, maxChunkSize, mutSize;
unsigned prob = seed % XML_FUZZ_PROB_ONE;
unsigned descSize = 0;
int i = 0;
while (1) {
unsigned descProb;
descSize = chunks[i].size;
descProb = chunks[i].mutateProb;
if (descSize == 0 ||
off + descSize > size ||
off + descSize >= maxSize ||
prob < descProb)
break;
off += descSize;
prob -= descProb;
i += 1;
}
chunkSize = size - off;
maxChunkSize = maxSize - off;
if (descSize != 0) {
if (chunkSize > descSize)
chunkSize = descSize;
if (maxChunkSize > descSize)
maxChunkSize = descSize;
}
mutSize = mutator(data + off, chunkSize, maxChunkSize);
if (size > off + chunkSize) {
size_t j;
for (j = mutSize; j < chunkSize; j++)
data[off + j] = 0;
ret = size;
} else {
ret = off + mutSize;
}
return ret;
}
+162
View File
@@ -0,0 +1,162 @@
/*
* fuzz.h: Common functions and macros for fuzzing.
*
* See Copyright for the status of this software.
*/
#ifndef __XML_FUZZERCOMMON_H__
#define __XML_FUZZERCOMMON_H__
#include <stddef.h>
#include <stdio.h>
#include <libxml/parser.h>
#ifdef __cplusplus
extern "C" {
#endif
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 207 || defined(__clang__)
#define ATTRIBUTE_UNUSED __attribute__((unused))
#else
#define ATTRIBUTE_UNUSED
#endif
#if defined(LIBXML_HTML_ENABLED)
#define HAVE_HTML_FUZZER
#endif
#if 1
#define HAVE_LINT_FUZZER
#endif
#if defined(LIBXML_READER_ENABLED)
#define HAVE_READER_FUZZER
#endif
#if defined(LIBXML_REGEXP_ENABLED)
#define HAVE_REGEXP_FUZZER
#endif
#if defined(LIBXML_SCHEMAS_ENABLED)
#define HAVE_SCHEMA_FUZZER
#endif
#if 1
#define HAVE_URI_FUZZER
#endif
#if defined(LIBXML_VALID_ENABLED)
#define HAVE_VALID_FUZZER
#endif
#if defined(LIBXML_XINCLUDE_ENABLED)
#define HAVE_XINCLUDE_FUZZER
#endif
#if 1
#define HAVE_XML_FUZZER
#endif
#if defined(LIBXML_XPTR_ENABLED)
#define HAVE_XPATH_FUZZER
#endif
#define XML_FUZZ_PROB_ONE (1u << 16)
typedef size_t
(*xmlFuzzMutator)(char *data, size_t size, size_t maxSize);
typedef struct {
unsigned size;
unsigned mutateProb;
} xmlFuzzChunkDesc;
int
LLVMFuzzerInitialize(int *argc, char ***argv);
int
LLVMFuzzerTestOneInput(const char *data, size_t size);
size_t
LLVMFuzzerMutate(char *data, size_t size, size_t maxSize);
size_t
LLVMFuzzerCustomMutator(char *data, size_t size, size_t maxSize,
unsigned seed);
void
xmlFuzzErrorFunc(void *ctx, const char *msg, ...);
void
xmlFuzzSErrorFunc(void *ctx, const xmlError *error);
void
xmlFuzzMemSetup(void);
void
xmlFuzzInjectFailure(size_t failurePos);
int
xmlFuzzMallocFailed(void);
void
xmlFuzzResetFailure(void);
void
xmlFuzzCheckFailureReport(const char *func, int oomReport, int ioReport);
void
xmlFuzzDataInit(const char *data, size_t size);
void
xmlFuzzDataCleanup(void);
void
xmlFuzzWriteInt(FILE *out, size_t v, int size);
size_t
xmlFuzzReadInt(int size);
size_t
xmlFuzzBytesRemaining(void);
const char *
xmlFuzzReadRemaining(size_t *size);
void
xmlFuzzWriteString(FILE *out, const char *str);
const char *
xmlFuzzReadString(size_t *size);
void
xmlFuzzReadEntities(void);
const char *
xmlFuzzMainUrl(void);
const char *
xmlFuzzMainEntity(size_t *size);
const char *
xmlFuzzSecondaryUrl(void);
const char *
xmlFuzzSecondaryEntity(size_t *size);
xmlParserErrors
xmlFuzzResourceLoader(void *data, const char *URL, const char *ID,
xmlResourceType type, xmlParserInputFlags flags,
xmlParserInputPtr *out);
char *
xmlSlurpFile(const char *path, size_t *size);
int
xmlFuzzOutputWrite(void *ctxt, const char *buffer, int len);
int
xmlFuzzOutputClose(void *ctxt);
size_t
xmlFuzzMutateChunks(const xmlFuzzChunkDesc *chunks,
char *data, size_t size, size_t maxSize, unsigned seed,
xmlFuzzMutator mutator);
#ifdef __cplusplus
}
#endif
#endif /* __XML_FUZZERCOMMON_H__ */
+658
View File
@@ -0,0 +1,658 @@
/*
* xmlSeed.c: Generate the XML seed corpus for fuzzing.
*
* See Copyright for the status of this software.
*/
#include <stdio.h>
#include <string.h>
#include <glob.h>
#include <libgen.h>
#include <sys/stat.h>
#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#include <libxml/HTMLparser.h>
#include <libxml/xinclude.h>
#include <libxml/xmlschemas.h>
#include "fuzz.h"
#define PATH_SIZE 500
#define SEED_BUF_SIZE 16384
#define EXPR_SIZE 4500
#define FLAG_READER (1 << 0)
#define FLAG_LINT (1 << 1)
#define FLAG_PUSH_CHUNK_SIZE (1 << 2)
typedef int
(*fileFunc)(const char *base, FILE *out);
typedef int
(*mainFunc)(const char *arg);
static struct {
FILE *out;
xmlHashTablePtr entities; /* Maps URLs to xmlFuzzEntityInfos */
xmlExternalEntityLoader oldLoader;
fileFunc processFile;
const char *fuzzer;
int counter;
char cwd[PATH_SIZE];
int flags;
} globalData;
#if defined(HAVE_SCHEMA_FUZZER) || \
defined(HAVE_XML_FUZZER)
/*
* A custom resource loader that writes all external DTDs or entities to a
* single file in the format expected by xmlFuzzResourceLoader.
*/
static xmlParserErrors
fuzzResourceRecorder(void *data ATTRIBUTE_UNUSED, const char *URL,
const char *ID ATTRIBUTE_UNUSED,
xmlResourceType type ATTRIBUTE_UNUSED,
xmlParserInputFlags flags,
xmlParserInputPtr *out) {
*out = NULL;
if (globalData.entities == NULL ||
xmlHashLookup(globalData.entities, BAD_CAST URL) == NULL) {
data = xmlSlurpFile(URL, NULL);
if (globalData.entities == NULL)
globalData.entities = xmlHashCreate(4);
xmlHashAddEntry(globalData.entities, (const xmlChar *) URL, data);
}
return(xmlNewInputFromUrl(URL, flags, out));
}
static void
fuzzRecorderInit(FILE *out) {
globalData.out = out;
globalData.entities = xmlHashCreate(8);
globalData.oldLoader = xmlGetExternalEntityLoader();
}
static void
fuzzRecorderWriteAndFree(void *entry, const xmlChar *file) {
char *data = entry;
xmlFuzzWriteString(globalData.out, (const char *) file);
xmlFuzzWriteString(globalData.out, data);
xmlFree(data);
}
static void
fuzzRecorderWrite(const char *file) {
xmlHashRemoveEntry(globalData.entities, (const xmlChar *) file,
fuzzRecorderWriteAndFree);
}
static void
fuzzRecorderCleanup(void) {
/* Write remaining entities (in random order). */
xmlHashFree(globalData.entities, fuzzRecorderWriteAndFree);
globalData.out = NULL;
globalData.entities = NULL;
globalData.oldLoader = NULL;
}
#endif
#ifdef HAVE_XML_FUZZER
static int
processXml(const char *docFile, FILE *out) {
int opts = XML_PARSE_NOENT | XML_PARSE_DTDLOAD;
xmlParserCtxtPtr ctxt;
xmlDocPtr doc;
if (globalData.flags & FLAG_LINT) {
/* Switches */
xmlFuzzWriteInt(out, 0, 4);
xmlFuzzWriteInt(out, 0, 4);
/* maxmem */
xmlFuzzWriteInt(out, 0, 4);
/* max-ampl */
xmlFuzzWriteInt(out, 0, 1);
/* pretty */
xmlFuzzWriteInt(out, 0, 1);
/* encode */
xmlFuzzWriteString(out, "");
/* pattern */
xmlFuzzWriteString(out, "");
/* xpath */
xmlFuzzWriteString(out, "");
} else {
/* Parser options. */
xmlFuzzWriteInt(out, opts, 4);
/* Max allocations. */
xmlFuzzWriteInt(out, 0, 4);
if (globalData.flags & FLAG_PUSH_CHUNK_SIZE) {
/* Chunk size for push parser */
xmlFuzzWriteInt(out, 256, 4);
}
if (globalData.flags & FLAG_READER) {
/* Initial reader program with a couple of OP_READs */
xmlFuzzWriteString(out, "\x01\x01\x01\x01\x01\x01\x01\x01");
}
}
fuzzRecorderInit(out);
ctxt = xmlNewParserCtxt();
xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
xmlCtxtSetResourceLoader(ctxt, fuzzResourceRecorder, NULL);
doc = xmlCtxtReadFile(ctxt, docFile, NULL, opts);
#ifdef LIBXML_XINCLUDE_ENABLED
{
xmlXIncludeCtxtPtr xinc = xmlXIncludeNewContext(doc);
xmlXIncludeSetErrorHandler(xinc, xmlFuzzSErrorFunc, NULL);
xmlXIncludeSetResourceLoader(xinc, fuzzResourceRecorder, NULL);
xmlXIncludeSetFlags(xinc, opts);
xmlXIncludeProcessNode(xinc, (xmlNodePtr) doc);
xmlXIncludeFreeContext(xinc);
}
#endif
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctxt);
fuzzRecorderWrite(docFile);
fuzzRecorderCleanup();
return(0);
}
#endif
#ifdef HAVE_HTML_FUZZER
static int
processHtml(const char *docFile, FILE *out) {
char buf[SEED_BUF_SIZE];
FILE *file;
size_t size;
/* Parser options. */
xmlFuzzWriteInt(out, 0, 4);
/* Max allocations. */
xmlFuzzWriteInt(out, 0, 4);
/* Copy file */
file = fopen(docFile, "rb");
if (file == NULL) {
fprintf(stderr, "couldn't open %s\n", docFile);
return(0);
}
do {
size = fread(buf, 1, SEED_BUF_SIZE, file);
if (size > 0)
fwrite(buf, 1, size, out);
} while (size == SEED_BUF_SIZE);
fclose(file);
return(0);
}
#endif
#if defined(HAVE_HTML_FUZZER) || \
defined(HAVE_XML_FUZZER)
static int
processPattern(const char *pattern) {
glob_t globbuf;
int ret = 0;
int res;
size_t i;
res = glob(pattern, 0, NULL, &globbuf);
if (res == GLOB_NOMATCH)
return(0);
if (res != 0) {
fprintf(stderr, "couldn't match pattern %s\n", pattern);
return(-1);
}
for (i = 0; i < globbuf.gl_pathc; i++) {
struct stat statbuf;
char outPath[PATH_SIZE];
char *dirBuf = NULL;
char *baseBuf = NULL;
const char *path, *dir, *base;
FILE *out = NULL;
int dirChanged = 0;
size_t size;
path = globbuf.gl_pathv[i];
if ((stat(path, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode)))
continue;
dirBuf = (char *) xmlCharStrdup(path);
baseBuf = (char *) xmlCharStrdup(path);
if ((dirBuf == NULL) || (baseBuf == NULL)) {
fprintf(stderr, "memory allocation failed\n");
ret = -1;
goto error;
}
dir = dirname(dirBuf);
base = basename(baseBuf);
size = snprintf(outPath, sizeof(outPath), "seed/%s/%s",
globalData.fuzzer, base);
if (size >= PATH_SIZE) {
fprintf(stderr, "creating path failed\n");
ret = -1;
goto error;
}
out = fopen(outPath, "wb");
if (out == NULL) {
fprintf(stderr, "couldn't open %s for writing\n", outPath);
ret = -1;
goto error;
}
if (chdir(dir) != 0) {
fprintf(stderr, "couldn't chdir to %s\n", dir);
ret = -1;
goto error;
}
dirChanged = 1;
if (globalData.processFile(base, out) != 0)
ret = -1;
error:
if (out != NULL)
fclose(out);
xmlFree(dirBuf);
xmlFree(baseBuf);
if ((dirChanged) && (chdir(globalData.cwd) != 0)) {
fprintf(stderr, "couldn't chdir to %s\n", globalData.cwd);
ret = -1;
break;
}
}
globfree(&globbuf);
return(ret);
}
#endif
#if defined(HAVE_SCHEMA_FUZZER)
static int
processSchema(const char *xsdFile, const char *xmlFile, FILE *out) {
xmlSchemaPtr schema;
xmlSchemaParserCtxtPtr pctxt;
/* Max allocations. */
xmlFuzzWriteInt(out, 0, 4);
fuzzRecorderInit(out);
pctxt = xmlSchemaNewParserCtxt(xsdFile);
xmlSchemaSetParserStructuredErrors(pctxt, xmlFuzzSErrorFunc, NULL);
xmlSchemaSetResourceLoader(pctxt, fuzzResourceRecorder, NULL);
schema = xmlSchemaParse(pctxt);
xmlSchemaFreeParserCtxt(pctxt);
if (schema != NULL) {
xmlSchemaValidCtxtPtr vctxt;
xmlParserCtxtPtr ctxt;
xmlDocPtr doc;
ctxt = xmlNewParserCtxt();
xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
xmlCtxtSetResourceLoader(ctxt, fuzzResourceRecorder, NULL);
doc = xmlCtxtReadFile(ctxt, xmlFile, NULL, XML_PARSE_NOENT);
xmlFreeParserCtxt(ctxt);
vctxt = xmlSchemaNewValidCtxt(schema);
xmlSchemaSetValidStructuredErrors(vctxt, xmlFuzzSErrorFunc, NULL);
xmlSchemaValidateDoc(vctxt, doc);
xmlSchemaFreeValidCtxt(vctxt);
xmlFreeDoc(doc);
xmlSchemaFree(schema);
}
fuzzRecorderWrite(xsdFile);
fuzzRecorderWrite(xmlFile);
fuzzRecorderCleanup();
return(0);
}
static int
processSchemaPattern(const char *pattern) {
glob_t globbuf;
int ret = 0;
int res;
size_t i;
res = glob(pattern, 0, NULL, &globbuf);
if (res == GLOB_NOMATCH)
return(0);
if (res != 0) {
fprintf(stderr, "couldn't match pattern %s\n", pattern);
return(-1);
}
for (i = 0; i < globbuf.gl_pathc; i++) {
glob_t globbuf2;
struct stat statbuf;
char xmlPattern[PATH_SIZE];
char *dirBuf = NULL;
char *baseBuf = NULL;
const char *path, *dir, *base;
size_t size, dirLen, baseLen, len, j;
path = globbuf.gl_pathv[i];
if ((stat(path, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode)))
continue;
dirBuf = (char *) xmlCharStrdup(path);
baseBuf = (char *) xmlCharStrdup(path);
if ((dirBuf == NULL) || (baseBuf == NULL)) {
fprintf(stderr, "memory allocation failed\n");
ret = -1;
goto error;
}
dir = dirname(dirBuf);
dirLen = strlen(dir);
base = basename(baseBuf);
baseLen = strlen(base);
len = strlen(path);
if (len <= 5)
continue;
/* Strip .xsl or _0.xsd suffix */
if (len > 6 && path[len - 6] == '_')
len -= 6;
else
len -= 4;
size = snprintf(xmlPattern, sizeof(xmlPattern), "%.*s_*.xml",
(int) len, path);
if (size >= PATH_SIZE) {
fprintf(stderr, "creating path failed\n");
ret = -1;
goto error;
}
res = glob(xmlPattern, 0, NULL, &globbuf2);
if (res == GLOB_NOMATCH)
goto error;
if (res != 0) {
fprintf(stderr, "couldn't match pattern %s\n", xmlPattern);
ret = -1;
goto error;
}
for (j = 0; j < globbuf2.gl_pathc; j++) {
char outPath[PATH_SIZE];
const char *xmlFile;
FILE *out = NULL;
xmlFile = globbuf2.gl_pathv[j];
len = strlen(xmlFile);
if (len < dirLen + 7)
continue;
if (len >= 6 && xmlFile[len - 6] == '_')
size = snprintf(outPath, sizeof(outPath), "seed/%s/%.*s_%c",
globalData.fuzzer, (int) baseLen - 4, base,
xmlFile[len - 5]);
else
size = snprintf(outPath, sizeof(outPath), "seed/%s/%.*s",
globalData.fuzzer, (int) baseLen - 4, base);
if (size >= PATH_SIZE) {
fprintf(stderr, "creating path failed\n");
ret = -1;
continue;
}
out = fopen(outPath, "wb");
if (out == NULL) {
fprintf(stderr, "couldn't open %s for writing\n", outPath);
ret = -1;
continue;
}
if (chdir(dir) != 0) {
fprintf(stderr, "couldn't chdir to %s\n", dir);
ret = -1;
} else {
if (processSchema(base, xmlFile + dirLen + 1, out) != 0)
ret = -1;
}
fclose(out);
if (chdir(globalData.cwd) != 0) {
fprintf(stderr, "couldn't chdir to %s\n", globalData.cwd);
ret = -1;
break;
}
}
globfree(&globbuf2);
error:
xmlFree(dirBuf);
xmlFree(baseBuf);
}
globfree(&globbuf);
return(ret);
}
#endif
#ifdef HAVE_XPATH_FUZZER
static int
processXPath(const char *testDir, const char *prefix, const char *name,
const char *data, const char *subdir, int xptr) {
char pattern[PATH_SIZE];
glob_t globbuf;
size_t i, size;
int ret = 0, res;
size = snprintf(pattern, sizeof(pattern), "%s/%s/%s*",
testDir, subdir, prefix);
if (size >= PATH_SIZE)
return(-1);
res = glob(pattern, 0, NULL, &globbuf);
if (res == GLOB_NOMATCH)
return(0);
if (res != 0) {
fprintf(stderr, "couldn't match pattern %s\n", pattern);
return(-1);
}
for (i = 0; i < globbuf.gl_pathc; i++) {
char *path = globbuf.gl_pathv[i];
struct stat statbuf;
FILE *in;
char expr[EXPR_SIZE];
if ((stat(path, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode)))
continue;
in = fopen(path, "rb");
if (in == NULL) {
ret = -1;
continue;
}
while (fgets(expr, EXPR_SIZE, in) != NULL) {
char outPath[PATH_SIZE];
FILE *out;
int j;
for (j = 0; expr[j] != 0; j++)
if (expr[j] == '\r' || expr[j] == '\n')
break;
expr[j] = 0;
size = snprintf(outPath, sizeof(outPath), "seed/xpath/%s-%d",
name, globalData.counter);
if (size >= PATH_SIZE) {
ret = -1;
continue;
}
out = fopen(outPath, "wb");
if (out == NULL) {
ret = -1;
continue;
}
/* Max allocations. */
xmlFuzzWriteInt(out, 0, 4);
if (xptr) {
xmlFuzzWriteString(out, expr);
} else {
char xptrExpr[EXPR_SIZE+100];
/* Wrap XPath expressions as XPointer */
snprintf(xptrExpr, sizeof(xptrExpr), "xpointer(%s)", expr);
xmlFuzzWriteString(out, xptrExpr);
}
xmlFuzzWriteString(out, data);
fclose(out);
globalData.counter++;
}
fclose(in);
}
globfree(&globbuf);
return(ret);
}
static int
processXPathDir(const char *testDir) {
char pattern[PATH_SIZE];
glob_t globbuf;
size_t i, size;
int ret = 0;
globalData.counter = 1;
if (processXPath(testDir, "", "expr", "<d></d>", "expr", 0) != 0)
ret = -1;
size = snprintf(pattern, sizeof(pattern), "%s/docs/*", testDir);
if (size >= PATH_SIZE)
return(1);
if (glob(pattern, 0, NULL, &globbuf) != 0)
return(1);
for (i = 0; i < globbuf.gl_pathc; i++) {
char *path = globbuf.gl_pathv[i];
char *data;
const char *docFile;
data = xmlSlurpFile(path, NULL);
if (data == NULL) {
ret = -1;
continue;
}
docFile = basename(path);
globalData.counter = 1;
if (processXPath(testDir, docFile, docFile, data, "tests", 0) != 0)
ret = -1;
if (processXPath(testDir, docFile, docFile, data, "xptr", 1) != 0)
ret = -1;
if (processXPath(testDir, docFile, docFile, data, "xptr-xp1", 1) != 0)
ret = -1;
xmlFree(data);
}
globfree(&globbuf);
return(ret);
}
#endif
int
main(int argc, const char **argv) {
mainFunc processArg = NULL;
const char *fuzzer;
int ret = 0;
int i;
if (argc < 3) {
fprintf(stderr, "usage: seed [FUZZER] [PATTERN...]\n");
return(1);
}
fuzzer = argv[1];
if (strcmp(fuzzer, "html") == 0) {
#ifdef HAVE_HTML_FUZZER
processArg = processPattern;
globalData.flags |= FLAG_PUSH_CHUNK_SIZE;
globalData.processFile = processHtml;
#endif
} else if (strcmp(fuzzer, "lint") == 0) {
#ifdef HAVE_LINT_FUZZER
processArg = processPattern;
globalData.flags |= FLAG_LINT;
globalData.processFile = processXml;
#endif
} else if (strcmp(fuzzer, "reader") == 0) {
#ifdef HAVE_READER_FUZZER
processArg = processPattern;
globalData.flags |= FLAG_READER;
globalData.processFile = processXml;
#endif
} else if (strcmp(fuzzer, "schema") == 0) {
#ifdef HAVE_SCHEMA_FUZZER
processArg = processSchemaPattern;
#endif
} else if (strcmp(fuzzer, "valid") == 0) {
#ifdef HAVE_VALID_FUZZER
processArg = processPattern;
globalData.processFile = processXml;
#endif
} else if (strcmp(fuzzer, "xinclude") == 0) {
#ifdef HAVE_XINCLUDE_FUZZER
processArg = processPattern;
globalData.processFile = processXml;
#endif
} else if (strcmp(fuzzer, "xml") == 0) {
#ifdef HAVE_XML_FUZZER
processArg = processPattern;
globalData.flags |= FLAG_PUSH_CHUNK_SIZE;
globalData.processFile = processXml;
#endif
} else if (strcmp(fuzzer, "xpath") == 0) {
#ifdef HAVE_XPATH_FUZZER
processArg = processXPathDir;
#endif
} else {
fprintf(stderr, "unknown fuzzer %s\n", fuzzer);
return(1);
}
globalData.fuzzer = fuzzer;
if (getcwd(globalData.cwd, PATH_SIZE) == NULL) {
fprintf(stderr, "couldn't get current directory\n");
return(1);
}
if (processArg != NULL)
for (i = 2; i < argc; i++)
processArg(argv[i]);
return(ret);
}
+236
View File
@@ -0,0 +1,236 @@
/*
* html.c: a libFuzzer target to test several HTML parser interfaces.
*
* See Copyright for the status of this software.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libxml/HTMLparser.h>
#include <libxml/HTMLtree.h>
#include <libxml/catalog.h>
#include "fuzz.h"
int
LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
char ***argv ATTRIBUTE_UNUSED) {
xmlFuzzMemSetup();
xmlInitParser();
#ifdef LIBXML_CATALOG_ENABLED
xmlInitializeCatalog();
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
return 0;
}
int
LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlParserCtxtPtr ctxt;
htmlDocPtr doc;
const char *docBuffer;
size_t failurePos, docSize, maxChunkSize;
int opts, errorCode;
#ifdef LIBXML_OUTPUT_ENABLED
xmlOutputBufferPtr out = NULL;
#endif
xmlFuzzDataInit(data, size);
opts = (int) xmlFuzzReadInt(4);
failurePos = xmlFuzzReadInt(4) % (size + 100);
maxChunkSize = xmlFuzzReadInt(4) % (size + size / 8 + 1);
if (maxChunkSize == 0)
maxChunkSize = 1;
docBuffer = xmlFuzzReadRemaining(&docSize);
if (docBuffer == NULL) {
xmlFuzzDataCleanup();
return(0);
}
/* Pull parser */
xmlFuzzInjectFailure(failurePos);
ctxt = htmlNewParserCtxt();
if (ctxt == NULL) {
errorCode = XML_ERR_NO_MEMORY;
} else {
xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
doc = htmlCtxtReadMemory(ctxt, docBuffer, docSize, NULL, NULL, opts);
errorCode = ctxt->errNo;
xmlFuzzCheckFailureReport("htmlCtxtReadMemory",
errorCode == XML_ERR_NO_MEMORY,
errorCode == XML_IO_EIO);
if (doc != NULL) {
xmlDocPtr copy;
#ifdef LIBXML_OUTPUT_ENABLED
const xmlChar *content;
/*
* Also test the serializer. Call htmlDocContentDumpOutput with our
* own buffer to avoid encoding the output. The HTML encoding is
* excruciatingly slow (see htmlEntityValueLookup).
*/
out = xmlAllocOutputBuffer(NULL);
htmlDocContentDumpOutput(out, doc, NULL);
content = xmlOutputBufferGetContent(out);
xmlFuzzCheckFailureReport("htmlDocContentDumpOutput",
content == NULL, 0);
if (content == NULL) {
xmlOutputBufferClose(out);
out = NULL;
}
#endif
copy = xmlCopyDoc(doc, 1);
xmlFuzzCheckFailureReport("xmlCopyNode", copy == NULL, 0);
xmlFreeDoc(copy);
xmlFreeDoc(doc);
}
htmlFreeParserCtxt(ctxt);
}
/* Push parser */
#ifdef LIBXML_PUSH_ENABLED
xmlFuzzInjectFailure(failurePos);
ctxt = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL,
XML_CHAR_ENCODING_NONE);
if (ctxt != NULL) {
size_t consumed;
int errorCodePush, numChunks, maxChunks;
xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
htmlCtxtUseOptions(ctxt, opts);
consumed = 0;
numChunks = 0;
maxChunks = 50 + docSize / 100;
while (numChunks == 0 ||
(consumed < docSize && numChunks < maxChunks)) {
size_t chunkSize;
int terminate;
numChunks += 1;
chunkSize = docSize - consumed;
if (numChunks < maxChunks && chunkSize > maxChunkSize) {
chunkSize = maxChunkSize;
terminate = 0;
} else {
terminate = 1;
}
htmlParseChunk(ctxt, docBuffer + consumed, chunkSize, terminate);
consumed += chunkSize;
}
errorCodePush = ctxt->errNo;
xmlFuzzCheckFailureReport("htmlParseChunk",
errorCodePush == XML_ERR_NO_MEMORY,
errorCodePush == XML_IO_EIO);
doc = ctxt->myDoc;
/*
* Push and pull parser differ in when exactly they
* stop parsing, and the error code is the *last* error
* reported, so we can't check whether the codes match.
*/
if (errorCode != XML_ERR_NO_MEMORY &&
errorCode != XML_IO_EIO &&
errorCodePush != XML_ERR_NO_MEMORY &&
errorCodePush != XML_IO_EIO &&
(errorCode == XML_ERR_OK) != (errorCodePush == XML_ERR_OK)) {
fprintf(stderr, "pull/push parser error mismatch: %d != %d\n",
errorCode, errorCodePush);
#if 0
FILE *f = fopen("c.html", "wb");
fwrite(docBuffer, docSize, 1, f);
fclose(f);
fprintf(stderr, "opts: %X\n", opts);
#endif
abort();
}
#ifdef LIBXML_OUTPUT_ENABLED
/*
* Verify that pull and push parser produce the same result.
*
* The NOBLANKS option doesn't work reliably in push mode.
*/
if ((opts & XML_PARSE_NOBLANKS) == 0 &&
errorCode == XML_ERR_OK &&
errorCodePush == XML_ERR_OK &&
out != NULL) {
xmlOutputBufferPtr outPush;
const xmlChar *content, *contentPush;
outPush = xmlAllocOutputBuffer(NULL);
htmlDocContentDumpOutput(outPush, doc, NULL);
content = xmlOutputBufferGetContent(out);
contentPush = xmlOutputBufferGetContent(outPush);
if (content != NULL && contentPush != NULL) {
size_t outSize = xmlOutputBufferGetSize(out);
if (outSize != xmlOutputBufferGetSize(outPush) ||
memcmp(content, contentPush, outSize) != 0) {
fprintf(stderr, "pull/push parser roundtrip "
"mismatch\n");
#if 0
FILE *f = fopen("c.html", "wb");
fwrite(docBuffer, docSize, 1, f);
fclose(f);
fprintf(stderr, "opts: %X\n", opts);
fprintf(stderr, "---\n%s\n---\n%s\n---\n",
xmlOutputBufferGetContent(out),
xmlOutputBufferGetContent(outPush));
#endif
abort();
}
}
xmlOutputBufferClose(outPush);
}
#endif
xmlFreeDoc(doc);
htmlFreeParserCtxt(ctxt);
}
#endif
/* Cleanup */
#ifdef LIBXML_OUTPUT_ENABLED
xmlOutputBufferClose(out);
#endif
xmlFuzzInjectFailure(0);
xmlFuzzDataCleanup();
xmlResetLastError();
return(0);
}
size_t
LLVMFuzzerCustomMutator(char *data, size_t size, size_t maxSize,
unsigned seed) {
static const xmlFuzzChunkDesc chunks[] = {
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* opts */
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* failurePos */
{ 0, 0 }
};
return xmlFuzzMutateChunks(chunks, data, size, maxSize, seed,
LLVMFuzzerMutate);
}
+124
View File
@@ -0,0 +1,124 @@
elem_a="<a></a>"
elem_abbr="<abbr></abbr>"
elem_acronym="<acronym></acronym>"
elem_address="<address></address>"
elem_applet="<applet></applet>"
elem_area="<area>"
elem_b="<b></b>"
elem_base="<base>"
elem_basefont="<basefont>"
elem_bdo="<bdo></bdo>"
elem_big="<big></big>"
elem_blockquote="<blockquote></blockquote>"
elem_body="<body></body>"
elem_br="<br>"
elem_button="<button></button>"
elem_caption="<caption></caption>"
elem_center="<center></center>"
elem_cite="<cite></cite>"
elem_code="<code></code>"
elem_col="<col>"
elem_colgroup="<colgroup></colgroup>"
elem_dd="<dd></dd>"
elem_del="<del></del>"
elem_dfn="<dfn></dfn>"
elem_dir="<dir></dir>"
elem_div="<div></div>"
elem_dl="<dl></dl>"
elem_dt="<dt></dt>"
elem_em="<em></em>"
elem_embed="<embed></embed>"
elem_fieldset="<fieldset></fieldset>"
elem_font="<font></font>"
elem_form="<form></form>"
elem_frame="<frame>"
elem_frameset="<frameset></frameset>"
elem_h1="<h1></h1>"
elem_h2="<h2></h2>"
elem_h3="<h3></h3>"
elem_h4="<h4></h4>"
elem_h5="<h5></h5>"
elem_h6="<h6></h6>"
elem_head="<head></head>"
elem_hr="<hr>"
elem_html="<html></html>"
elem_i="<i></i>"
elem_iframe="<iframe></iframe>"
elem_img="<img>"
elem_input="<input>"
elem_ins="<ins></ins>"
elem_isindex="<isindex>"
elem_kbd="<kbd></kbd>"
elem_label="<label></label>"
elem_legend="<legend></legend>"
elem_li="<li></li>"
elem_link="<link>"
elem_map="<map></map>"
elem_menu="<menu></menu>"
elem_meta="<meta>"
elem_noframes="<noframes></noframes>"
elem_noscript="<noscript></noscript>"
elem_object="<object></object>"
elem_ol="<ol></ol>"
elem_optgroup="<optgroup></optgroup>"
elem_option="<option></option>"
elem_p="<p></p>"
elem_param="<param>"
elem_pre="<pre></pre>"
elem_q="<q></q>"
elem_s="<s></s>"
elem_samp="<samp></samp>"
elem_script="<script></script>"
elem_select="<select></select>"
elem_small="<small></small>"
elem_span="<span></span>"
elem_strike="<strike></strike>"
elem_strong="<strong></strong>"
elem_style="<style></style>"
elem_sub="<sub></sub>"
elem_sup="<sup></sup>"
elem_table="<table></table>"
elem_tbody="<tbody></tbody>"
elem_td="<td></td>"
elem_textarea="<textarea></textarea>"
elem_tfoot="<tfoot></tfoot>"
elem_th="<th></th>"
elem_thead="<thead></thead>"
elem_title="<title></title>"
elem_tr="<tr></tr>"
elem_tt="<tt></tt>"
elem_u="<u></u>"
elem_ul="<ul></ul>"
elem_var="<var></var>"
attr_id=" id=\"\""
attr_style=" style=\"\""
comment="<!-- -->"
doctype="<!DOCTYPE d>"
doctype_system="<!DOCTYPE s SYSTEM \"u\">"
doctype_public="<!DOCTYPE p PUBLIC \"i\" \"u\">"
pi="<?a?>"
ref_lt="&lt;"
ref_gt="&gt;"
ref_amp="&amp;"
ref_apos="&apos;"
ref_quot="&quot;"
ref_dec="&#9;"
ref_hex="&#xA;"
cs_utf8="UTF-8"
cs_utf16="UTF-16"
cs_utf16le="UTF-16LE"
cs_utf16be="UTF-16BE"
cs_ucs2="UCS-2"
cs_ucs4="UCS-4"
cs_latin1="ISO-8859-1"
cs_ascii="ASCII"
cs_ebcdic="EBCDIC"
cs_iso2022jp="ISO-2022-JP"
cs_shift_jis="SHIFT_JIS"
cs_euc_jp="EUC-JP"
+256
View File
@@ -0,0 +1,256 @@
/*
* lint.c: a libFuzzer target to test the xmllint executable.
*
* See Copyright for the status of this software.
*/
#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"
/*
* Untested options:
*
* --memory: Requires temp file
*
* --catalogs: Requires XML catalogs
*
* --dtdvalid:
* --dtdvalidfpi: Requires an external DTD
*
* --output: Writes to disk
*
* --path: Requires cooperation with resource loader
*
* --relaxng:
* --schema:
* --schematron: Requires schemas
*
* --shell: We could pipe fuzz data to stdin but this is probably
* not worth it.
*/
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;
/* Redirect stdout to /dev/null */
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;
}
/*
* Use four main parsing modes with equal probability
*/
switch (uval & 3) {
case 0:
/* XML parser */
break;
case 1:
/* HTML parser */
pushArg("--html");
break;
case 2:
/* XML reader */
pushArg("--stream");
break;
case 3:
/* SAX parser */
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 }, /* switches */
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* maxmem */
{ 1, XML_FUZZ_PROB_ONE / 100 }, /* maxAmpl */
{ 1, XML_FUZZ_PROB_ONE / 100 }, /* pretty */
{ 0, 0 }
};
return xmlFuzzMutateChunks(chunks, data, size, maxSize, seed,
LLVMFuzzerMutate);
}
+192
View File
@@ -0,0 +1,192 @@
xml_decl="<?xml version='1.0'?>"
xml_decl_standalone="<?xml version='1.0' standalone='1'?>"
xml_decl_latin1="<?xml version='1.0' encoding='ISO-8859-1'?>"
elem_start_end="<a></a>"
elem_empty="<a/>"
elem_ns_start_end="<a:a xmlns:a='a'></a:a>"
elem_ns_empty="<a:a xmlns:a='a'/>"
attr=" a='a'"
ns_decl=" xmlns:a='a'"
ns_default=" xmlns='a'"
ns_prefix="a:"
cdata_section="<![CDATA[ ]]>"
comment="<!-- -->"
pi="<?a?>"
doctype="<!DOCTYPE a []>"
doctype_system="<!DOCTYPE a SYSTEM 'a' []>"
doctype_system="<!DOCTYPE a PUBLIC 'a' 'a' []>"
elem_decl_any="<!ELEMENT a ANY>"
elem_decl_empty="<!ELEMENT a EMPTY>"
elem_decl_children="<!ELEMENT a (a)>"
elem_decl_mixed="<!ELEMENT a (#PCDATA|a)>"
elem_children_choice="|a"
elem_children_seq=",a"
elem_children_sub_choice="|(a)"
elem_children_sub_seq=",(a)"
elem_quant_any="*"
elem_quant_opt="?"
elem_quant_some="+"
attr_decl_cdata_req="<!ATTLIST a a CDATA #REQUIRED>"
attr_decl_cdata_imp="<!ATTLIST a a CDATA #IMPLIED>"
attr_decl_cdata_def="<!ATTLIST a a CDATA 'a'>"
attr_decl_cdata_fix="<!ATTLIST a a CDATA #FIXED 'a'>"
attr_decl_id_imp="<!ATTLIST a a ID #IMPLIED>"
attr_decl_id_req="<!ATTLIST a a ID #REQUIRED>"
attr_decl_id_def="<!ATTLIST a a ID 'a'>"
attr_decl_id_fix="<!ATTLIST a a ID #FIXED 'a'>"
attr_decl_idref_imp="<!ATTLIST a a IDREF #IMPLIED>"
attr_decl_idref_req="<!ATTLIST a a IDREF #REQUIRED>"
attr_decl_idref_def="<!ATTLIST a a IDREF 'a'>"
attr_decl_idref_fix="<!ATTLIST a a IDREF #FIXED 'a'>"
attr_decl_idrefs_imp="<!ATTLIST a a IDREFS #IMPLIED>"
attr_decl_idrefs_req="<!ATTLIST a a IDREFS #REQUIRED>"
attr_decl_idrefs_def="<!ATTLIST a a IDREFS 'a'>"
attr_decl_idrefs_fix="<!ATTLIST a a IDREFS #FIXED 'a'>"
attr_decl_entity_imp="<!ATTLIST a a ENTITY #IMPLIED>"
attr_decl_entity_req="<!ATTLIST a a ENTITY #REQUIRED>"
attr_decl_entity_def="<!ATTLIST a a ENTITY 'a'>"
attr_decl_entity_fix="<!ATTLIST a a ENTITY #FIXED 'a'>"
attr_decl_entities_imp="<!ATTLIST a a ENTITIES #IMPLIED>"
attr_decl_entities_req="<!ATTLIST a a ENTITIES #REQUIRED>"
attr_decl_entities_def="<!ATTLIST a a ENTITIES 'a'>"
attr_decl_entities_fix="<!ATTLIST a a ENTITIES #FIXED 'a'>"
attr_decl_nmtoken_imp="<!ATTLIST a a NMTOKEN #IMPLIED>"
attr_decl_nmtoken_req="<!ATTLIST a a NMTOKEN #REQUIRED>"
attr_decl_nmtoken_def="<!ATTLIST a a NMTOKEN 'a'>"
attr_decl_nmtoken_fix="<!ATTLIST a a NMTOKEN #FIXED 'a'>"
attr_decl_nmtokens_imp="<!ATTLIST a a NMTOKENS #IMPLIED>"
attr_decl_nmtokens_req="<!ATTLIST a a NMTOKENS #REQUIRED>"
attr_decl_nmtokens_def="<!ATTLIST a a NMTOKENS 'a'>"
attr_decl_nmtokens_fix="<!ATTLIST a a NMTOKENS #FIXED 'a'>"
attr_decl_enum_imp="<!ATTLIST a a (a) #IMPLIED>"
attr_decl_enum_req="<!ATTLIST a a (a) #REQUIRED>"
attr_decl_enum_def="<!ATTLIST a a (a) 'a'>"
attr_decl_enum_fix="<!ATTLIST a a (a) #FIXED 'a'>"
attr_decl_notation_imp="<!ATTLIST a a NOTATION (a) #IMPLIED>"
attr_decl_notation_req="<!ATTLIST a a NOTATION (a) #REQUIRED>"
attr_decl_notation_def="<!ATTLIST a a NOTATION (a) 'a'>"
attr_decl_notation_fix="<!ATTLIST a a NOTATION (a) #FIXED 'a'>"
include_sect="<![INCLUDE[ ]]>"
ignore_sect="<![IGNORE[ ]]>"
ge_decl="<!ENTITY a 'a'>"
ge_decl_system="<!ENTITY a SYSTEM 'a'>"
ge_decl_system_ndata="<!ENTITY a SYSTEM 'a' NDATA a>"
ge_decl_public="<!ENTITY a PUBLIC 'a' 'a'>"
ge_decl_public_ndata="<!ENTITY a PUBLIC 'a' 'a' NDATA a>"
pe_decl="<!ENTITY % a 'a'>"
pe_decl_system="<!ENTITY % a SYSTEM 'a'>"
pe_decl_public="<!ENTITY % a PUBLIC 'a' 'a'>"
char_ref_dec="&#60;"
char_ref_hex="&#x3c;"
char_ref_quoted="&#38;#60;"
ge_ref_lt="&lt;"
ge_ref_gt="&gt;"
ge_ref_amp="&amp;"
ge_ref_apos="&apos;"
ge_ref_quot="&quot;"
ge_ref="&a;"
ge_ref_quoted="&#38;a;"
pe_ref="%a;"
pe_ref_quoted="&#37;a;"
notation_decl_public="<!NOTATION a PUBLIC 'a'>"
notation_decl_system="<!NOTATION a SYSTEM 'a'>"
cs_utf8="UTF-8"
cs_utf16="UTF-16"
cs_utf16le="UTF-16LE"
cs_utf16be="UTF-16BE"
cs_ucs2="UCS-2"
cs_ucs4="UCS-4"
cs_latin1="ISO-8859-1"
cs_ascii="ASCII"
cs_ebcdic="EBCDIC"
cs_iso2022jp="ISO-2022-JP"
cs_shift_jis="SHIFT_JIS"
cs_euc_jp="EUC-JP"
# XPath
axis_ancestor="ancestor::"
axis_ancestor_or_self="ancestor-or-self::"
axis_attribute="attribute::"
axis_attribute_abbrev="@"
axis_child="child::"
axis_descendant="descendant::"
axis_descendant_or_self="descendant-or-self::"
axis_following="following::"
axis_following_sibling="following-sibling::"
axis_namespace="namespace::"
axis_parent="parent::"
axis_preceding="preceding::"
axis_preceding_siblings="preceding-sibling::"
axis_self="self::"
node_test_ns="a:"
val_num="=(1.0)"
val_str_sq="=('a')"
val_str_dq="=(\"a\")"
val_node_set="=(*)"
val_elem="=(b)"
step_root="/"
step_descendant="//"
step_any="//*"
step_any_l="*//"
step_elem="//b"
step_ns_elem="//a:a"
step_comment="//comment()"
step_node="//node()"
step_node_l="node()//"
step_pi="//processing-instruction()"
step_text="//text()"
step_parent="../"
op_plus="+1"
op_minus=" - 1"
op_neg="-"
op_mul="*1"
op_div=" div 1"
op_mod=" mod 1"
op_and=" and 1"
op_or=" or 1"
op_ne="!=1"
op_lt="<1"
op_gt=">1"
op_le="<=1"
op_ge=">=1"
op_predicate_num="[1]"
op_predicate_last="[last()]"
op_predicate_str="['a']"
op_predicate="[1=1]"
op_arg_num=",1"
op_arg_str=",'a'"
op_arg_node=",*"
op_union="|//b"
var_num="=$f"
var_bool="=$b"
var_str="=$s"
var_node_set="=$n"
# Unicode
utf8_2="\xC3\x84"
utf8_3="\xE2\x80\x9C"
utf8_4="\xF0\x9F\x98\x80"
+62
View File
@@ -0,0 +1,62 @@
#!/bin/bash -eu
# OSS-Fuzz integration, see
# https://github.com/google/oss-fuzz/tree/master/projects/libxml2
# Add extra UBSan checks
if [ "$SANITIZER" = undefined ]; then
extra_checks="integer,float-divide-by-zero"
extra_cflags="-fsanitize=$extra_checks -fno-sanitize-recover=$extra_checks"
export CFLAGS="$CFLAGS $extra_cflags"
export CXXFLAGS="$CXXFLAGS $extra_cflags"
fi
# Don't enable zlib with MSan
if [ "$SANITIZER" = memory ]; then
CONFIG=''
else
CONFIG='--with-zlib'
fi
# Workaround for a LeakSanitizer crashes,
# see https://github.com/google/oss-fuzz/issues/11798.
if [ "$ARCHITECTURE" = "aarch64" ]; then
export ASAN_OPTIONS=detect_leaks=0
fi
export V=1
./autogen.sh \
--disable-shared \
--without-debug \
--without-http \
--without-python \
$CONFIG
make -j$(nproc)
cd fuzz
make clean-corpus
make fuzz.o
for fuzzer in \
api html lint reader regexp schema uri valid xinclude xml xpath
do
OBJS="$fuzzer.o"
if [ "$fuzzer" = lint ]; then
OBJS="$OBJS ../xmllint.o ../shell.o"
fi
make $OBJS
# Link with $CXX
$CXX $CXXFLAGS \
$OBJS fuzz.o \
-o $OUT/$fuzzer \
$LIB_FUZZING_ENGINE \
../.libs/libxml2.a -Wl,-Bstatic -lz -Wl,-Bdynamic
if [ $fuzzer != api ]; then
[ -e seed/$fuzzer ] || make seed/$fuzzer.stamp
zip -j $OUT/${fuzzer}_seed_corpus.zip seed/$fuzzer/*
fi
done
cp *.dict *.options $OUT/
+568
View File
@@ -0,0 +1,568 @@
/*
* reader.c: a libFuzzer target to test the XML Reader API.
*
* See Copyright for the status of this software.
*/
#include <libxml/catalog.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlerror.h>
#include <libxml/xmlreader.h>
#include <libxml/xmlsave.h>
#include "fuzz.h"
#include <string.h>
#if 0
#define DEBUG
#endif
typedef enum {
OP_READ = 1,
OP_READ_INNER_XML,
OP_READ_OUTER_XML,
OP_READ_STRING,
OP_READ_ATTRIBUTE_VALUE,
OP_ATTRIBUTE_COUNT,
OP_DEPTH,
OP_HAS_ATTRIBUTES,
OP_HAS_VALUE,
OP_IS_DEFAULT,
OP_IS_EMPTY_ELEMENT,
OP_NODE_TYPE,
OP_QUOTE_CHAR,
OP_READ_STATE,
OP_IS_NAMESPACE_DECL,
OP_CONST_BASE_URI,
OP_CONST_LOCAL_NAME,
OP_CONST_NAME,
OP_CONST_NAMESPACE_URI,
OP_CONST_PREFIX,
OP_CONST_XML_LANG,
OP_CONST_VALUE,
OP_BASE_URI,
OP_LOCAL_NAME,
OP_NAME,
OP_NAMESPACE_URI,
OP_PREFIX,
OP_XML_LANG,
OP_VALUE,
OP_CLOSE,
OP_GET_ATTRIBUTE_NO,
OP_GET_ATTRIBUTE,
OP_GET_ATTRIBUTE_NS,
OP_GET_REMAINDER,
OP_LOOKUP_NAMESPACE,
OP_MOVE_TO_ATTRIBUTE_NO,
OP_MOVE_TO_ATTRIBUTE,
OP_MOVE_TO_ATTRIBUTE_NS,
OP_MOVE_TO_FIRST_ATTRIBUTE,
OP_MOVE_TO_NEXT_ATTRIBUTE,
OP_MOVE_TO_ELEMENT,
OP_NORMALIZATION,
OP_CONST_ENCODING,
OP_GET_PARSER_PROP,
OP_CURRENT_NODE,
OP_GET_PARSER_LINE_NUMBER,
OP_GET_PARSER_COLUMN_NUMBER,
OP_PRESERVE,
OP_CURRENT_DOC,
OP_EXPAND,
OP_NEXT,
OP_NEXT_SIBLING,
OP_IS_VALID,
OP_CONST_XML_VERSION,
OP_STANDALONE,
OP_BYTE_CONSUMED,
OP_MAX
} opType;
static void
startOp(const char *name) {
(void) name;
#ifdef DEBUG
fprintf(stderr, "%s\n", name);
#endif
}
int
LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
char ***argv ATTRIBUTE_UNUSED) {
xmlFuzzMemSetup();
xmlInitParser();
#ifdef LIBXML_CATALOG_ENABLED
xmlInitializeCatalog();
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
return 0;
}
int
LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlTextReaderPtr reader;
xmlDocPtr doc = NULL;
const xmlError *error;
const char *docBuffer;
const unsigned char *program;
size_t failurePos, docSize, programSize, i;
size_t totalStringSize = 0;
int opts;
int oomReport = 0;
xmlFuzzDataInit(data, size);
opts = (int) xmlFuzzReadInt(4);
failurePos = xmlFuzzReadInt(4) % (size + 100);
program = (const unsigned char *) xmlFuzzReadString(&programSize);
if (programSize > 1000)
programSize = 1000;
xmlFuzzReadEntities();
docBuffer = xmlFuzzMainEntity(&docSize);
if (docBuffer == NULL)
goto exit;
#ifdef DEBUG
fprintf(stderr, "Input document (%d bytes):\n", (int) docSize);
for (i = 0; (size_t) i < docSize; i++) {
int c = (unsigned char) docBuffer[i];
if ((c == '\n' || (c >= 0x20 && c <= 0x7E)))
putc(c, stderr);
else
fprintf(stderr, "\\x%02X", c);
}
fprintf(stderr, "\nEOF\n");
#endif
xmlFuzzInjectFailure(failurePos);
reader = xmlReaderForMemory(docBuffer, docSize, NULL, NULL, opts);
if (reader == NULL)
goto exit;
xmlTextReaderSetStructuredErrorHandler(reader, xmlFuzzSErrorFunc, NULL);
xmlTextReaderSetResourceLoader(reader, xmlFuzzResourceLoader, NULL);
i = 0;
while (i < programSize) {
int op = program[i++];
#define READ_BYTE() (i < programSize ? program[i++] : 0)
#define FREE_STRING(str) \
do { \
if (str != NULL) { \
totalStringSize += strlen((char *) str); \
xmlFree(str); \
} \
} while (0)
switch (op & 0x3F) {
case OP_READ:
default:
startOp("Read");
xmlTextReaderRead(reader);
break;
case OP_READ_INNER_XML: {
xmlChar *result;
startOp("ReadInnerXml");
result = xmlTextReaderReadInnerXml(reader);
FREE_STRING(result);
break;
}
case OP_READ_OUTER_XML: {
xmlChar *result;
startOp("ReadOuterXml");
result = xmlTextReaderReadOuterXml(reader);
FREE_STRING(result);
break;
}
case OP_READ_STRING: {
xmlChar *result;
startOp("ReadString");
result = xmlTextReaderReadString(reader);
FREE_STRING(result);
break;
}
case OP_READ_ATTRIBUTE_VALUE:
startOp("ReadAttributeValue");
xmlTextReaderReadAttributeValue(reader);
break;
case OP_ATTRIBUTE_COUNT:
startOp("AttributeCount");
xmlTextReaderAttributeCount(reader);
break;
case OP_DEPTH:
startOp("Depth");
xmlTextReaderDepth(reader);
break;
case OP_HAS_ATTRIBUTES:
startOp("HasAttributes");
xmlTextReaderHasAttributes(reader);
break;
case OP_HAS_VALUE:
startOp("HasValue");
xmlTextReaderHasValue(reader);
break;
case OP_IS_DEFAULT:
startOp("IsDefault");
xmlTextReaderIsDefault(reader);
break;
case OP_IS_EMPTY_ELEMENT:
startOp("IsEmptyElement");
xmlTextReaderIsEmptyElement(reader);
break;
case OP_NODE_TYPE:
startOp("NodeType");
xmlTextReaderNodeType(reader);
break;
case OP_QUOTE_CHAR:
startOp("QuoteChar");
xmlTextReaderQuoteChar(reader);
break;
case OP_READ_STATE:
startOp("ReadState");
xmlTextReaderReadState(reader);
break;
case OP_IS_NAMESPACE_DECL:
startOp("IsNamespaceDecl");
xmlTextReaderIsNamespaceDecl(reader);
break;
case OP_CONST_BASE_URI:
startOp("ConstBaseUri");
xmlTextReaderConstBaseUri(reader);
break;
case OP_CONST_LOCAL_NAME:
startOp("ConstLocalName");
xmlTextReaderConstLocalName(reader);
break;
case OP_CONST_NAME:
startOp("ConstName");
xmlTextReaderConstName(reader);
break;
case OP_CONST_NAMESPACE_URI:
startOp("ConstNamespaceUri");
xmlTextReaderConstNamespaceUri(reader);
break;
case OP_CONST_PREFIX:
startOp("ConstPrefix");
xmlTextReaderConstPrefix(reader);
break;
case OP_CONST_XML_LANG:
startOp("ConstXmlLang");
xmlTextReaderConstXmlLang(reader);
oomReport = -1;
break;
case OP_CONST_VALUE:
startOp("ConstValue");
xmlTextReaderConstValue(reader);
break;
case OP_BASE_URI: {
xmlChar *result;
startOp("BaseUri");
result = xmlTextReaderBaseUri(reader);
FREE_STRING(result);
break;
}
case OP_LOCAL_NAME: {
xmlChar *result;
startOp("LocalName");
result = xmlTextReaderLocalName(reader);
FREE_STRING(result);
break;
}
case OP_NAME: {
xmlChar *result;
startOp("Name");
result = xmlTextReaderName(reader);
FREE_STRING(result);
break;
}
case OP_NAMESPACE_URI: {
xmlChar *result;
startOp("NamespaceUri");
result = xmlTextReaderNamespaceUri(reader);
FREE_STRING(result);
break;
}
case OP_PREFIX: {
xmlChar *result;
startOp("Prefix");
result = xmlTextReaderPrefix(reader);
FREE_STRING(result);
break;
}
case OP_XML_LANG: {
xmlChar *result;
startOp("XmlLang");
result = xmlTextReaderXmlLang(reader);
oomReport = -1;
FREE_STRING(result);
break;
}
case OP_VALUE: {
xmlChar *result;
startOp("Value");
result = xmlTextReaderValue(reader);
FREE_STRING(result);
break;
}
case OP_CLOSE:
startOp("Close");
if (doc == NULL)
doc = xmlTextReaderCurrentDoc(reader);
xmlTextReaderClose(reader);
break;
case OP_GET_ATTRIBUTE_NO: {
xmlChar *result;
int no = READ_BYTE();
startOp("GetAttributeNo");
result = xmlTextReaderGetAttributeNo(reader, no);
FREE_STRING(result);
break;
}
case OP_GET_ATTRIBUTE: {
const xmlChar *name = xmlTextReaderConstName(reader);
xmlChar *result;
startOp("GetAttribute");
result = xmlTextReaderGetAttribute(reader, name);
FREE_STRING(result);
break;
}
case OP_GET_ATTRIBUTE_NS: {
const xmlChar *localName, *namespaceUri;
xmlChar *result;
startOp("GetAttributeNs");
localName = xmlTextReaderConstLocalName(reader);
namespaceUri = xmlTextReaderConstNamespaceUri(reader);
result = xmlTextReaderGetAttributeNs(reader, localName,
namespaceUri);
FREE_STRING(result);
break;
}
case OP_GET_REMAINDER:
startOp("GetRemainder");
if (doc == NULL)
doc = xmlTextReaderCurrentDoc(reader);
xmlFreeParserInputBuffer(xmlTextReaderGetRemainder(reader));
break;
case OP_LOOKUP_NAMESPACE: {
const xmlChar *prefix = xmlTextReaderConstPrefix(reader);
xmlChar *result;
startOp("LookupNamespace");
result = xmlTextReaderLookupNamespace(reader, prefix);
FREE_STRING(result);
break;
}
case OP_MOVE_TO_ATTRIBUTE_NO: {
int no = READ_BYTE();
startOp("MoveToAttributeNo");
xmlTextReaderMoveToAttributeNo(reader, no);
break;
}
case OP_MOVE_TO_ATTRIBUTE: {
const xmlChar *name = xmlTextReaderConstName(reader);
startOp("MoveToAttribute");
xmlTextReaderMoveToAttribute(reader, name);
break;
}
case OP_MOVE_TO_ATTRIBUTE_NS: {
const xmlChar *localName, *namespaceUri;
startOp("MoveToAttributeNs");
localName = xmlTextReaderConstLocalName(reader);
namespaceUri = xmlTextReaderConstNamespaceUri(reader);
xmlTextReaderMoveToAttributeNs(reader, localName,
namespaceUri);
break;
}
case OP_MOVE_TO_FIRST_ATTRIBUTE:
startOp("MoveToFirstAttribute");
xmlTextReaderMoveToFirstAttribute(reader);
break;
case OP_MOVE_TO_NEXT_ATTRIBUTE:
startOp("MoveToNextAttribute");
xmlTextReaderMoveToNextAttribute(reader);
break;
case OP_MOVE_TO_ELEMENT:
startOp("MoveToElement");
xmlTextReaderMoveToElement(reader);
break;
case OP_NORMALIZATION:
startOp("Normalization");
xmlTextReaderNormalization(reader);
break;
case OP_CONST_ENCODING:
startOp("ConstEncoding");
xmlTextReaderConstEncoding(reader);
break;
case OP_GET_PARSER_PROP: {
int prop = READ_BYTE();
startOp("GetParserProp");
xmlTextReaderGetParserProp(reader, prop);
break;
}
case OP_CURRENT_NODE:
startOp("CurrentNode");
xmlTextReaderCurrentNode(reader);
break;
case OP_GET_PARSER_LINE_NUMBER:
startOp("GetParserLineNumber");
xmlTextReaderGetParserLineNumber(reader);
break;
case OP_GET_PARSER_COLUMN_NUMBER:
startOp("GetParserColumnNumber");
xmlTextReaderGetParserColumnNumber(reader);
break;
case OP_PRESERVE:
startOp("Preserve");
xmlTextReaderPreserve(reader);
break;
case OP_CURRENT_DOC: {
xmlDocPtr result;
startOp("CurrentDoc");
result = xmlTextReaderCurrentDoc(reader);
if (doc == NULL)
doc = result;
break;
}
case OP_EXPAND:
startOp("Expand");
xmlTextReaderExpand(reader);
break;
case OP_NEXT:
startOp("Next");
xmlTextReaderNext(reader);
break;
case OP_NEXT_SIBLING:
startOp("NextSibling");
xmlTextReaderNextSibling(reader);
break;
case OP_IS_VALID:
startOp("IsValid");
xmlTextReaderIsValid(reader);
break;
case OP_CONST_XML_VERSION:
startOp("ConstXmlVersion");
xmlTextReaderConstXmlVersion(reader);
break;
case OP_STANDALONE:
startOp("Standalone");
xmlTextReaderStandalone(reader);
break;
case OP_BYTE_CONSUMED:
startOp("ByteConsumed");
xmlTextReaderByteConsumed(reader);
oomReport = -1;
break;
}
if (totalStringSize > docSize * 2)
break;
}
error = xmlTextReaderGetLastError(reader);
if (error->code == XML_ERR_NO_MEMORY)
oomReport = 1;
xmlFuzzCheckFailureReport("reader", oomReport, error->code == XML_IO_EIO);
xmlFreeTextReader(reader);
if (doc != NULL)
xmlFreeDoc(doc);
exit:
xmlFuzzInjectFailure(0);
xmlFuzzDataCleanup();
xmlResetLastError();
return(0);
}
size_t
LLVMFuzzerCustomMutator(char *data, size_t size, size_t maxSize,
unsigned seed) {
static const xmlFuzzChunkDesc chunks[] = {
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* opts */
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* failurePos */
{ 0, 0 }
};
return xmlFuzzMutateChunks(chunks, data, size, maxSize, seed,
LLVMFuzzerMutate);
}
+2
View File
@@ -0,0 +1,2 @@
[libfuzzer]
dict = xml.dict
+63
View File
@@ -0,0 +1,63 @@
/*
* regexp.c: a libFuzzer target to test the regexp module.
*
* See Copyright for the status of this software.
*/
#include <stdio.h>
#include <stdlib.h>
#include <libxml/xmlregexp.h>
#include "fuzz.h"
int
LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
char ***argv ATTRIBUTE_UNUSED) {
xmlFuzzMemSetup();
return 0;
}
int
LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlRegexpPtr regexp;
size_t failurePos;
const char *str1;
if (size > 200)
return(0);
xmlFuzzDataInit(data, size);
failurePos = xmlFuzzReadInt(4) % (size * 8 + 100);
str1 = xmlFuzzReadString(NULL);
xmlFuzzInjectFailure(failurePos);
regexp = xmlRegexpCompile(BAD_CAST str1);
if (xmlFuzzMallocFailed() && regexp != NULL) {
fprintf(stderr, "malloc failure not reported\n");
abort();
}
/* xmlRegexpExec has pathological performance in too many cases. */
#if 0
xmlRegexpExec(regexp, BAD_CAST str2);
#endif
xmlRegFreeRegexp(regexp);
xmlFuzzInjectFailure(0);
xmlFuzzDataCleanup();
xmlResetLastError();
return 0;
}
size_t
LLVMFuzzerCustomMutator(char *data, size_t size, size_t maxSize,
unsigned seed) {
static const xmlFuzzChunkDesc chunks[] = {
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* failurePos */
{ 0, 0 }
};
return xmlFuzzMutateChunks(chunks, data, size, maxSize, seed,
LLVMFuzzerMutate);
}
+155
View File
@@ -0,0 +1,155 @@
quant_any="*"
quant_opt="?"
quant_some="+"
quant_num="{1,2}"
dot="."
branch="|a"
parens="()"
parens_inner=")("
pos_group="[a]"
neg_group="[^a]"
class_subtraction="[a-[b]]"
esc_space="\\s"
esc_initial="\\i"
esc_name="\\c"
esc_digit="\\d"
esc_word="\\w"
cat_letter="\\p{L}"
cat_mark="\\p{M}"
cat_number="\\p{N}"
cat_punct="\\p{P}"
cat_sym="\\p{S}"
cat_sep="\\p{Z}"
cat_other="\\p{C}"
block_aegean_numbers="\\p{IsAegeanNumbers}"
block_alphabetic_presentation_forms="\\p{IsAlphabeticPresentationForms}"
block_arabic="\\p{IsArabic}"
block_arabic_presentation_forms_a="\\p{IsArabicPresentationFormsA}"
block_arabic_presentation_forms_b="\\p{IsArabicPresentationFormsB}"
block_armenian="\\p{IsArmenian}"
block_arrows="\\p{IsArrows}"
block_basic_latin="\\p{IsBasicLatin}"
block_bengali="\\p{IsBengali}"
block_block_elements="\\p{IsBlockElements}"
block_bopomofo="\\p{IsBopomofo}"
block_bopomofo_extended="\\p{IsBopomofoExtended}"
block_box_drawing="\\p{IsBoxDrawing}"
block_braille_patterns="\\p{IsBraillePatterns}"
block_buhid="\\p{IsBuhid}"
block_byzantine_musical_symbols="\\p{IsByzantineMusicalSymbols}"
block_c_j_k_compatibility="\\p{IsCJKCompatibility}"
block_c_j_k_compatibility_forms="\\p{IsCJKCompatibilityForms}"
block_c_j_k_compatibility_ideographs="\\p{IsCJKCompatibilityIdeographs}"
block_c_j_k_compatibility_ideographs_supplement="\\p{IsCJKCompatibilityIdeographsSupplement}"
block_c_j_k_radicals_supplement="\\p{IsCJKRadicalsSupplement}"
block_c_j_k_symbolsand_punctuation="\\p{IsCJKSymbolsandPunctuation}"
block_c_j_k_unified_ideographs="\\p{IsCJKUnifiedIdeographs}"
block_c_j_k_unified_ideographs_extension_a="\\p{IsCJKUnifiedIdeographsExtensionA}"
block_cjk_unified_ideographs_extension_b="\\p{IsCJKUnifiedIdeographsExtensionB}"
block_cherokee="\\p{IsCherokee}"
block_combining_diacritical_marks="\\p{IsCombiningDiacriticalMarks}"
block_combining_diacritical_marksfor_symbols="\\p{IsCombiningDiacriticalMarksforSymbols}"
block_combining_half_marks="\\p{IsCombiningHalfMarks}"
block_combining_marksfor_symbols="\\p{IsCombiningMarksforSymbols}"
block_control_pictures="\\p{IsControlPictures}"
block_currency_symbols="\\p{IsCurrencySymbols}"
block_cypriot_syllabary="\\p{IsCypriotSyllabary}"
block_cyrillic="\\p{IsCyrillic}"
block_cyrillic_supplement="\\p{IsCyrillicSupplement}"
block_deseret="\\p{IsDeseret}"
block_devanagari="\\p{IsDevanagari}"
block_dingbats="\\p{IsDingbats}"
block_enclosed_alphanumerics="\\p{IsEnclosedAlphanumerics}"
block_enclosed_cjk_lettersand_months="\\p{IsEnclosedCJKLettersandMonths}"
block_ethiopic="\\p{IsEthiopic}"
block_general_punctuation="\\p{IsGeneralPunctuation}"
block_geometric_shapes="\\p{IsGeometricShapes}"
block_georgian="\\p{IsGeorgian}"
block_gothic="\\p{IsGothic}"
block_greek="\\p{IsGreek}"
block_greek_extended="\\p{IsGreekExtended}"
block_greekand_coptic="\\p{IsGreekandCoptic}"
block_gujarati="\\p{IsGujarati}"
block_gurmukhi="\\p{IsGurmukhi}"
block_halfwidthand_fullwidth_forms="\\p{IsHalfwidthandFullwidthForms}"
block_hangul_compatibility_jamo="\\p{IsHangulCompatibilityJamo}"
block_hangul_jamo="\\p{IsHangulJamo}"
block_hangul_syllables="\\p{IsHangulSyllables}"
block_hanunoo="\\p{IsHanunoo}"
block_hebrew="\\p{IsHebrew}"
block_high_private_use_surrogates="\\p{IsHighPrivateUseSurrogates}"
block_high_surrogates="\\p{IsHighSurrogates}"
block_hiragana="\\p{IsHiragana}"
block_ipa_extensions="\\p{IsIPAExtensions}"
block_ideographic_description_characters="\\p{IsIdeographicDescriptionCharacters}"
block_kanbun="\\p{IsKanbun}"
block_kangxi_radicals="\\p{IsKangxiRadicals}"
block_kannada="\\p{IsKannada}"
block_katakana="\\p{IsKatakana}"
block_katakana_phonetic_extensions="\\p{IsKatakanaPhoneticExtensions}"
block_khmer="\\p{IsKhmer}"
block_khmer_symbols="\\p{IsKhmerSymbols}"
block_lao="\\p{IsLao}"
block_latin1Supplement="\\p{IsLatin1Supplement}"
block_latin_extended_a="\\p{IsLatinExtendedA}"
block_latin_extended_b="\\p{IsLatinExtendedB}"
block_latin_extended_additional="\\p{IsLatinExtendedAdditional}"
block_letterlike_symbols="\\p{IsLetterlikeSymbols}"
block_limbu="\\p{IsLimbu}"
block_linear_b_ideograms="\\p{IsLinearBIdeograms}"
block_linear_b_syllabary="\\p{IsLinearBSyllabary}"
block_low_surrogates="\\p{IsLowSurrogates}"
block_malayalam="\\p{IsMalayalam}"
block_mathematical_alphanumeric_symbols="\\p{IsMathematicalAlphanumericSymbols}"
block_mathematical_operators="\\p{IsMathematicalOperators}"
block_miscellaneous_mathematical_symbols_a="\\p{IsMiscellaneousMathematicalSymbolsA}"
block_miscellaneous_mathematical_symbols_b="\\p{IsMiscellaneousMathematicalSymbolsB}"
block_miscellaneous_symbols="\\p{IsMiscellaneousSymbols}"
block_miscellaneous_symbolsand_arrows="\\p{IsMiscellaneousSymbolsandArrows}"
block_miscellaneous_technical="\\p{IsMiscellaneousTechnical}"
block_mongolian="\\p{IsMongolian}"
block_musical_symbols="\\p{IsMusicalSymbols}"
block_myanmar="\\p{IsMyanmar}"
block_number_forms="\\p{IsNumberForms}"
block_ogham="\\p{IsOgham}"
block_old_italic="\\p{IsOldItalic}"
block_optical_character_recognition="\\p{IsOpticalCharacterRecognition}"
block_oriya="\\p{IsOriya}"
block_osmanya="\\p{IsOsmanya}"
block_phonetic_extensions="\\p{IsPhoneticExtensions}"
block_private_use="\\p{IsPrivateUse}"
block_private_use_area="\\p{IsPrivateUseArea}"
block_runic="\\p{IsRunic}"
block_shavian="\\p{IsShavian}"
block_sinhala="\\p{IsSinhala}"
block_small_form_variants="\\p{IsSmallFormVariants}"
block_spacing_modifier_letters="\\p{IsSpacingModifierLetters}"
block_specials="\\p{IsSpecials}"
block_superscriptsand_subscripts="\\p{IsSuperscriptsandSubscripts}"
block_supplemental_arrows_a="\\p{IsSupplementalArrowsA}"
block_supplemental_arrows_b="\\p{IsSupplementalArrowsB}"
block_supplemental_mathematical_operators="\\p{IsSupplementalMathematicalOperators}"
block_supplementary_private_use_area_a="\\p{IsSupplementaryPrivateUseAreaA}"
block_supplementary_private_use_area_b="\\p{IsSupplementaryPrivateUseAreaB}"
block_syriac="\\p{IsSyriac}"
block_tagalog="\\p{IsTagalog}"
block_tagbanwa="\\p{IsTagbanwa}"
block_tags="\\p{IsTags}"
block_tai_le="\\p{IsTaiLe}"
block_tai_xuan_jing_symbols="\\p{IsTaiXuanJingSymbols}"
block_tamil="\\p{IsTamil}"
block_telugu="\\p{IsTelugu}"
block_thaana="\\p{IsThaana}"
block_thai="\\p{IsThai}"
block_tibetan="\\p{IsTibetan}"
block_ugaritic="\\p{IsUgaritic}"
block_unified_canadian_aboriginal_syllabics="\\p{IsUnifiedCanadianAboriginalSyllabics}"
block_variation_selectors="\\p{IsVariationSelectors}"
block_variation_selectors_supplement="\\p{IsVariationSelectorsSupplement}"
block_yi_radicals="\\p{IsYiRadicals}"
block_yi_syllables="\\p{IsYiSyllables}"
block_yijing_hexagram_symbols="\\p{IsYijingHexagramSymbols}"
+91
View File
@@ -0,0 +1,91 @@
/*
* schema.c: a libFuzzer target to test the XML Schema processor.
*
* See Copyright for the status of this software.
*/
#ifndef XML_DEPRECATED
#define XML_DEPRECATED
#endif
#include <libxml/catalog.h>
#include <libxml/xmlschemas.h>
#include <libxml/xmlschemastypes.h>
#include "fuzz.h"
int
LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
char ***argv ATTRIBUTE_UNUSED) {
xmlFuzzMemSetup();
xmlInitParser();
#ifdef LIBXML_CATALOG_ENABLED
xmlInitializeCatalog();
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
return 0;
}
int
LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlSchemaParserCtxtPtr pctxt;
xmlSchemaPtr schema;
size_t failurePos;
if (size > 200000)
return(0);
xmlFuzzDataInit(data, size);
failurePos = xmlFuzzReadInt(4) % (size + 100);
xmlFuzzReadEntities();
xmlFuzzInjectFailure(failurePos);
pctxt = xmlSchemaNewParserCtxt(xmlFuzzMainUrl());
xmlSchemaSetParserStructuredErrors(pctxt, xmlFuzzSErrorFunc, NULL);
xmlSchemaSetResourceLoader(pctxt, xmlFuzzResourceLoader, NULL);
schema = xmlSchemaParse(pctxt);
xmlSchemaFreeParserCtxt(pctxt);
if (schema != NULL) {
xmlSchemaValidCtxtPtr vctxt;
xmlParserCtxtPtr ctxt;
xmlDocPtr doc;
ctxt = xmlNewParserCtxt();
xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
doc = xmlCtxtReadFile(ctxt, xmlFuzzSecondaryUrl(), NULL,
XML_PARSE_NOENT);
xmlFreeParserCtxt(ctxt);
vctxt = xmlSchemaNewValidCtxt(schema);
xmlSchemaSetValidStructuredErrors(vctxt, xmlFuzzSErrorFunc, NULL);
xmlSchemaValidateDoc(vctxt, doc);
xmlSchemaFreeValidCtxt(vctxt);
xmlFreeDoc(doc);
xmlSchemaFree(schema);
}
xmlFuzzInjectFailure(0);
xmlFuzzDataCleanup();
xmlResetLastError();
xmlSchemaCleanupTypes();
return(0);
}
size_t
LLVMFuzzerCustomMutator(char *data, size_t size, size_t maxSize,
unsigned seed) {
static const xmlFuzzChunkDesc chunks[] = {
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* failurePos */
{ 0, 0 }
};
return xmlFuzzMutateChunks(chunks, data, size, maxSize, seed,
LLVMFuzzerMutate);
}
+55
View File
@@ -0,0 +1,55 @@
# TODO: Add more language elements
xs_annotation="<xs:annotation></xs:annotation>"
xs_attribute="<xs:attribute name='a'></xs:attribute>"
xs_attribute_required="<xs:attribute name='a' use='required'></xs:attribute>"
xs_element="<xs:element name='e'></xs:element>"
# Primitive datatypes
type_string=" type='xs:string'"
type_boolean=" type='xs:boolean'"
type_decimal=" type='xs:decimal'"
type_float=" type='xs:float'"
type_double=" type='xs:double'"
type_date_time=" type='xs:dateTime'"
type_time=" type='xs:time'"
type_date=" type='xs:date'"
type_g_year_month=" type='xs:gYearMonth'"
type_g_year=" type='xs:gYear'"
type_g_month_day=" type='xs:gMonthDay'"
type_g_day=" type='xs:gDay'"
type_g_month=" type='xs:gMonth'"
type_hex_binary=" type='xs:hexBinary'"
type_base64_binary=" type='xs:base64Binary'"
type_any_uri=" type='xs:anyURI'"
type_qname=" type='xs:QName'"
type_notation=" type='xs:NOTATION'"
# Occurs
occurs_min=" minOccurs='1'"
occurs_max=" maxOccurs='9'"
occurs_max_unbounded=" maxOccurs='unbounded'"
# Simple type
xs_restriction_integer="<xs:simpleType><xs:restriction base='xs:integer'></xs:restriction></xs:simpleType>"
xs_restriction_string="<xs:simpleType><xs:restriction base='xs:string'></xs:restriction></xs:simpleType>"
xs_list="<xs:simpleType><xs:list></xs:list></xs:simpleType>"
xs_union="<xs:simpleType><xs:union></xs:union></xs:simpleType>"
# Restrictions
xs_min_exclusive="<xs:minExclusive value='0'/>"
xs_min_inclusive="<xs:minInclusive value='0'/>"
xs_max_exclusive="<xs:maxExclusive value='9'/>"
xs_max_inclusive="<xs:maxInclusive value='9'/>"
xs_total_digits="<xs:totalDigits value='3'/>"
xs_fraction_digits="<xs:fractionDigits value='3'/>"
xs_length="<xs:length value='3'/>"
xs_min_length="<xs:minLength value='3'/>"
xs_max_length="<xs:maxLength value='3'/>"
xs_enumeration="<xs:enumeration value='a'/>"
xs_white_space_collapse="<xs:whiteSpace value='collapse'/>"
xs_white_space_preserve="<xs:whiteSpace value='preserve'/>"
xs_white_space_replace="<xs:whiteSpace value='replace'/>"
xs_pattern="<xs:pattern value='a'/>"
+39
View File
@@ -0,0 +1,39 @@
#!/bin/sh
set -e
fuzzer="$1"
if [ -z "$fuzzer" ]; then
echo usage: $0 fuzzer
exit 1
fi
# Rebuild the project with coverage enabled
make distclean
export CC=clang
export CXX=clang++
export CFLAGS=" \
-O1 -gline-tables-only \
-fsanitize=fuzzer-no-link \
-fprofile-instr-generate -fcoverage-mapping \
-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION"
sh autogen.sh --without-python
make -j5
rm default.profraw
# Process corpus once
cd fuzz
make $fuzzer
./$fuzzer -runs=1 corpus/$fuzzer
# Generate HTML report
llvm-profdata merge default.profraw -o default.profdata
llvm-cov show -format=html -output-dir=report \
-instr-profile default.profdata \
../.libs/libxml2.so
rm default.profraw default.profdata
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
set -e
fuzzer="$1"
if [ -z "$fuzzer" ]; then
echo usage: $0 fuzzer
exit 1
fi
cd fuzz
make $fuzzer
if [ ! -e corpus/${fuzzer}_ ]; then
mv corpus/$fuzzer corpus/${fuzzer}_
fi
mkdir -p corpus/$fuzzer
./$fuzzer -merge=1 -use_value_profile=1 corpus/$fuzzer corpus/${fuzzer}_
rm -rf corpus/${fuzzer}_
+324
View File
@@ -0,0 +1,324 @@
/*
* testFuzzer.c: Test program for the custom entity loader used to fuzz
* with multiple inputs.
*
* See Copyright for the status of this software.
*/
#ifndef XML_DEPRECATED
#define XML_DEPRECATED
#endif
#include <string.h>
#include <glob.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlstring.h>
#include "fuzz.h"
size_t
LLVMFuzzerMutate(char *data, size_t size, size_t maxSize) {
(void) data;
(void) maxSize;
return size;
}
#ifdef HAVE_HTML_FUZZER
int fuzzHtmlInit(int *argc, char ***argv);
int fuzzHtml(const char *data, size_t size);
size_t fuzzHtmlMutate(char *data, size_t size, size_t maxSize,
unsigned seed);
#define LLVMFuzzerInitialize fuzzHtmlInit
#define LLVMFuzzerTestOneInput fuzzHtml
#define LLVMFuzzerCustomMutator fuzzHtmlMutate
#include "html.c"
#undef LLVMFuzzerInitialize
#undef LLVMFuzzerTestOneInput
#undef LLVMFuzzerCustomMutator
#endif
#ifdef HAVE_READER_FUZZER
int fuzzReaderInit(int *argc, char ***argv);
int fuzzReader(const char *data, size_t size);
size_t fuzzReaderMutate(char *data, size_t size, size_t maxSize,
unsigned seed);
#define LLVMFuzzerInitialize fuzzReaderInit
#define LLVMFuzzerTestOneInput fuzzReader
#define LLVMFuzzerCustomMutator fuzzReaderMutate
#include "reader.c"
#undef LLVMFuzzerInitialize
#undef LLVMFuzzerTestOneInput
#undef LLVMFuzzerCustomMutator
#endif
#ifdef HAVE_REGEXP_FUZZER
int fuzzRegexpInit(int *argc, char ***argv);
int fuzzRegexp(const char *data, size_t size);
size_t fuzzRegexpMutate(char *data, size_t size, size_t maxSize,
unsigned seed);
#define LLVMFuzzerInitialize fuzzRegexpInit
#define LLVMFuzzerTestOneInput fuzzRegexp
#define LLVMFuzzerCustomMutator fuzzRegexpMutate
#include "regexp.c"
#undef LLVMFuzzerInitialize
#undef LLVMFuzzerTestOneInput
#undef LLVMFuzzerCustomMutator
#endif
#ifdef HAVE_SCHEMA_FUZZER
int fuzzSchemaInit(int *argc, char ***argv);
int fuzzSchema(const char *data, size_t size);
size_t fuzzSchemaMutate(char *data, size_t size, size_t maxSize,
unsigned seed);
#define LLVMFuzzerInitialize fuzzSchemaInit
#define LLVMFuzzerTestOneInput fuzzSchema
#define LLVMFuzzerCustomMutator fuzzSchemaMutate
#include "schema.c"
#undef LLVMFuzzerInitialize
#undef LLVMFuzzerTestOneInput
#undef LLVMFuzzerCustomMutator
#endif
#ifdef HAVE_URI_FUZZER
int fuzzUriInit(int *argc, char ***argv);
int fuzzUri(const char *data, size_t size);
size_t fuzzUriMutate(char *data, size_t size, size_t maxSize,
unsigned seed);
#define LLVMFuzzerInitialize fuzzUriInit
#define LLVMFuzzerTestOneInput fuzzUri
#define LLVMFuzzerCustomMutator fuzzUriMutate
#include "uri.c"
#undef LLVMFuzzerInitialize
#undef LLVMFuzzerTestOneInput
#undef LLVMFuzzerCustomMutator
#endif
#ifdef HAVE_VALID_FUZZER
int fuzzValidInit(int *argc, char ***argv);
int fuzzValid(const char *data, size_t size);
size_t fuzzValidMutate(char *data, size_t size, size_t maxSize,
unsigned seed);
#define LLVMFuzzerInitialize fuzzValidInit
#define LLVMFuzzerTestOneInput fuzzValid
#define LLVMFuzzerCustomMutator fuzzValidMutate
#include "valid.c"
#undef LLVMFuzzerInitialize
#undef LLVMFuzzerTestOneInput
#undef LLVMFuzzerCustomMutator
#endif
#ifdef HAVE_XINCLUDE_FUZZER
int fuzzXIncludeInit(int *argc, char ***argv);
int fuzzXInclude(const char *data, size_t size);
size_t fuzzXIncludeMutate(char *data, size_t size, size_t maxSize,
unsigned seed);
#define LLVMFuzzerInitialize fuzzXIncludeInit
#define LLVMFuzzerTestOneInput fuzzXInclude
#define LLVMFuzzerCustomMutator fuzzXIncludeMutate
#include "xinclude.c"
#undef LLVMFuzzerInitialize
#undef LLVMFuzzerTestOneInput
#undef LLVMFuzzerCustomMutator
#endif
#ifdef HAVE_XML_FUZZER
int fuzzXmlInit(int *argc, char ***argv);
int fuzzXml(const char *data, size_t size);
size_t fuzzXmlMutate(char *data, size_t size, size_t maxSize,
unsigned seed);
#define LLVMFuzzerInitialize fuzzXmlInit
#define LLVMFuzzerTestOneInput fuzzXml
#define LLVMFuzzerCustomMutator fuzzXmlMutate
#include "xml.c"
#undef LLVMFuzzerInitialize
#undef LLVMFuzzerTestOneInput
#undef LLVMFuzzerCustomMutator
#endif
#ifdef HAVE_XPATH_FUZZER
int fuzzXPathInit(int *argc, char ***argv);
int fuzzXPath(const char *data, size_t size);
size_t fuzzXPathMutate(char *data, size_t size, size_t maxSize,
unsigned seed);
#define LLVMFuzzerInitialize fuzzXPathInit
#define LLVMFuzzerTestOneInput fuzzXPath
#define LLVMFuzzerCustomMutator fuzzXPathMutate
#include "xpath.c"
#undef LLVMFuzzerInitialize
#undef LLVMFuzzerTestOneInput
#undef LLVMFuzzerCustomMutator
#endif
typedef int
(*initFunc)(int *argc, char ***argv);
typedef int
(*fuzzFunc)(const char *data, size_t size);
typedef size_t
(*mutateFunc)(char *data, size_t size, size_t maxSize, unsigned seed);
int numInputs;
static int
testFuzzer(initFunc init, fuzzFunc fuzz, mutateFunc mutate,
const char *pattern) {
glob_t globbuf;
int ret = -1;
size_t i;
(void) mutate;
if (glob(pattern, 0, NULL, &globbuf) != 0) {
fprintf(stderr, "pattern %s matches no files\n", pattern);
return(-1);
}
if (init != NULL)
init(NULL, NULL);
for (i = 0; i < globbuf.gl_pathc; i++) {
const char *path = globbuf.gl_pathv[i];
char *data;
size_t size;
data = xmlSlurpFile(path, &size);
if (data == NULL) {
fprintf(stderr, "couldn't read %s\n", path);
goto error;
}
fuzz(data, size);
xmlFree(data);
numInputs++;
}
ret = 0;
error:
globfree(&globbuf);
return(ret);
}
#ifdef HAVE_XML_FUZZER
static int
testEntityLoader(void) {
xmlParserCtxtPtr ctxt;
static const char data[] =
"doc.xml\\\n"
"<!DOCTYPE doc SYSTEM \"doc.dtd\">\n"
"<doc>&ent;</doc>\\\n"
"doc.dtd\\\n"
"<!ELEMENT doc (#PCDATA)>\n"
"<!ENTITY ent SYSTEM \"ent.txt\">\\\n"
"ent.txt\\\n"
"Hello, world!\\\n";
const char *docBuffer, *url;
size_t docSize;
xmlDocPtr doc;
int ret = 0;
xmlFuzzDataInit(data, sizeof(data) - 1);
xmlFuzzReadEntities();
url = xmlFuzzMainUrl();
if (strcmp(url, "doc.xml") != 0) {
fprintf(stderr, "unexpected main url: %s\n", url);
ret = 1;
}
url = xmlFuzzSecondaryUrl();
if (strcmp(url, "doc.dtd") != 0) {
fprintf(stderr, "unexpected secondary url: %s\n", url);
ret = 1;
}
docBuffer = xmlFuzzMainEntity(&docSize);
ctxt = xmlNewParserCtxt();
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, NULL, NULL,
XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
xmlFreeParserCtxt(ctxt);
#ifdef LIBXML_OUTPUT_ENABLED
{
static xmlChar expected[] =
"<?xml version=\"1.0\"?>\n"
"<!DOCTYPE doc SYSTEM \"doc.dtd\">\n"
"<doc>Hello, world!</doc>\n";
xmlChar *out;
xmlDocDumpMemory(doc, &out, NULL);
if (xmlStrcmp(out, expected) != 0) {
fprintf(stderr, "Expected:\n%sGot:\n%s", expected, out);
ret = 1;
}
xmlFree(out);
}
#endif
xmlFreeDoc(doc);
xmlFuzzDataCleanup();
return(ret);
}
#endif
int
main(void) {
int ret = 0;
#ifdef HAVE_XML_FUZZER
if (testEntityLoader() != 0)
ret = 1;
#endif
#ifdef HAVE_HTML_FUZZER
if (testFuzzer(fuzzHtmlInit, fuzzHtml, fuzzHtmlMutate,
"seed/html/*") != 0)
ret = 1;
#endif
#ifdef HAVE_READER_FUZZER
if (testFuzzer(fuzzReaderInit, fuzzReader, fuzzReaderMutate,
"seed/reader/*") != 0)
ret = 1;
#endif
#ifdef HAVE_REGEXP_FUZZER
if (testFuzzer(fuzzRegexpInit, fuzzRegexp, fuzzRegexpMutate,
"seed/regexp/*") != 0)
ret = 1;
#endif
#ifdef HAVE_SCHEMA_FUZZER
if (testFuzzer(fuzzSchemaInit, fuzzSchema, fuzzSchemaMutate,
"seed/schema/*") != 0)
ret = 1;
#endif
#ifdef HAVE_URI_FUZZER
if (testFuzzer(fuzzUriInit, fuzzUri, fuzzUriMutate,
"seed/uri/*") != 0)
ret = 1;
#endif
#ifdef HAVE_VALID_FUZZER
if (testFuzzer(fuzzValidInit, fuzzValid, fuzzValidMutate,
"seed/valid/*") != 0)
ret = 1;
#endif
#ifdef HAVE_XINCLUDE_FUZZER
if (testFuzzer(fuzzXIncludeInit, fuzzXInclude, fuzzXIncludeMutate,
"seed/xinclude/*") != 0)
ret = 1;
#endif
#ifdef HAVE_XML_FUZZER
if (testFuzzer(fuzzXmlInit, fuzzXml, fuzzXmlMutate,
"seed/xml/*") != 0)
ret = 1;
#endif
#ifdef HAVE_XPATH_FUZZER
if (testFuzzer(fuzzXPathInit, fuzzXPath, fuzzXPathMutate,
"seed/xpath/*") != 0)
ret = 1;
#endif
if (ret == 0)
printf("Successfully tested %d inputs\n", numInputs);
return(ret);
}
+116
View File
@@ -0,0 +1,116 @@
/*
* uri.c: a libFuzzer target to test the URI module.
*
* See Copyright for the status of this software.
*/
#include <libxml/uri.h>
#include "fuzz.h"
int
LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
char ***argv ATTRIBUTE_UNUSED) {
xmlFuzzMemSetup();
return 0;
}
int
LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlURIPtr uri;
size_t failurePos;
const char *str1, *str2;
char *copy;
xmlChar *strRes;
int intRes;
if (size > 10000)
return(0);
xmlFuzzDataInit(data, size);
failurePos = xmlFuzzReadInt(4) % (size * 8 + 100);
str1 = xmlFuzzReadString(NULL);
str2 = xmlFuzzReadString(NULL);
xmlFuzzInjectFailure(failurePos);
xmlFuzzResetFailure();
intRes = xmlParseURISafe(str1, &uri);
xmlFuzzCheckFailureReport("xmlParseURISafe", intRes == -1, 0);
if (uri != NULL) {
xmlFuzzResetFailure();
strRes = xmlSaveUri(uri);
xmlFuzzCheckFailureReport("xmlSaveURI", strRes == NULL, 0);
xmlFree(strRes);
xmlFreeURI(uri);
}
xmlFreeURI(xmlParseURI(str1));
uri = xmlParseURIRaw(str1, 1);
xmlFree(xmlSaveUri(uri));
xmlFreeURI(uri);
xmlFuzzResetFailure();
strRes = BAD_CAST xmlURIUnescapeString(str1, -1, NULL);
xmlFuzzCheckFailureReport("xmlURIUnescapeString",
str1 != NULL && strRes == NULL, 0);
xmlFree(strRes);
xmlFree(xmlURIEscape(BAD_CAST str1));
xmlFuzzResetFailure();
strRes = xmlCanonicPath(BAD_CAST str1);
xmlFuzzCheckFailureReport("xmlCanonicPath",
str1 != NULL && strRes == NULL, 0);
xmlFree(strRes);
xmlFuzzResetFailure();
strRes = xmlPathToURI(BAD_CAST str1);
xmlFuzzCheckFailureReport("xmlPathToURI",
str1 != NULL && strRes == NULL, 0);
xmlFree(strRes);
xmlFuzzResetFailure();
intRes = xmlBuildURISafe(BAD_CAST str2, BAD_CAST str1, &strRes);
xmlFuzzCheckFailureReport("xmlBuildURISafe", intRes == -1, 0);
xmlFree(strRes);
xmlFree(xmlBuildURI(BAD_CAST str2, BAD_CAST str1));
xmlFuzzResetFailure();
intRes = xmlBuildRelativeURISafe(BAD_CAST str2, BAD_CAST str1, &strRes);
xmlFuzzCheckFailureReport("xmlBuildRelativeURISafe", intRes == -1, 0);
xmlFree(strRes);
xmlFree(xmlBuildRelativeURI(BAD_CAST str2, BAD_CAST str1));
xmlFuzzResetFailure();
strRes = xmlURIEscapeStr(BAD_CAST str1, BAD_CAST str2);
xmlFuzzCheckFailureReport("xmlURIEscapeStr",
str1 != NULL && strRes == NULL, 0);
xmlFree(strRes);
copy = (char *) xmlCharStrdup(str1);
xmlNormalizeURIPath(copy);
xmlFree(copy);
xmlFuzzInjectFailure(0);
xmlFuzzDataCleanup();
return 0;
}
size_t
LLVMFuzzerCustomMutator(char *data, size_t size, size_t maxSize,
unsigned seed) {
static const xmlFuzzChunkDesc chunks[] = {
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* failurePos */
{ 0, 0 }
};
return xmlFuzzMutateChunks(chunks, data, size, maxSize, seed,
LLVMFuzzerMutate);
}
+139
View File
@@ -0,0 +1,139 @@
/*
* valid.c: a libFuzzer target to test DTD validation.
*
* See Copyright for the status of this software.
*/
#include <libxml/catalog.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlerror.h>
#include "fuzz.h"
int
LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
char ***argv ATTRIBUTE_UNUSED) {
xmlFuzzMemSetup();
xmlInitParser();
#ifdef LIBXML_CATALOG_ENABLED
xmlInitializeCatalog();
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
return 0;
}
int
LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlParserCtxtPtr ctxt;
xmlDocPtr doc;
const char *docBuffer, *docUrl;
size_t failurePos, docSize;
int opts;
xmlFuzzDataInit(data, size);
opts = (int) xmlFuzzReadInt(4);
opts |= XML_PARSE_DTDVALID;
failurePos = xmlFuzzReadInt(4) % (size + 100);
xmlFuzzReadEntities();
docBuffer = xmlFuzzMainEntity(&docSize);
docUrl = xmlFuzzMainUrl();
if (docBuffer == NULL)
goto exit;
/* Pull parser */
xmlFuzzInjectFailure(failurePos);
ctxt = xmlNewParserCtxt();
if (ctxt != NULL) {
xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL, opts);
xmlFuzzCheckFailureReport("xmlCtxtReadMemory",
ctxt->errNo == XML_ERR_NO_MEMORY,
ctxt->errNo == XML_IO_EIO);
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctxt);
}
/* Post validation */
xmlFuzzInjectFailure(failurePos);
ctxt = xmlNewParserCtxt();
if (ctxt != NULL) {
xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL,
opts & ~XML_PARSE_DTDVALID);
xmlFuzzCheckFailureReport("xmlCtxtReadMemory",
doc == NULL && ctxt->errNo == XML_ERR_NO_MEMORY,
doc == NULL && ctxt->errNo == XML_IO_EIO);
if (doc != NULL) {
int valid = xmlCtxtValidateDocument(ctxt, doc);
xmlFuzzCheckFailureReport("xmlCtxtValidateDocument",
!valid && ctxt->errNo == XML_ERR_NO_MEMORY,
!valid && ctxt->errNo == XML_IO_EIO);
}
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctxt);
}
/* Push parser */
#ifdef LIBXML_PUSH_ENABLED
{
static const size_t maxChunkSize = 128;
size_t consumed, chunkSize;
xmlFuzzInjectFailure(failurePos);
/*
* FIXME: xmlCreatePushParserCtxt can still report OOM errors
* to stderr.
*/
xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, docUrl);
xmlSetGenericErrorFunc(NULL, NULL);
if (ctxt != NULL) {
xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
xmlCtxtUseOptions(ctxt, opts);
for (consumed = 0; consumed < docSize; consumed += chunkSize) {
chunkSize = docSize - consumed;
if (chunkSize > maxChunkSize)
chunkSize = maxChunkSize;
xmlParseChunk(ctxt, docBuffer + consumed, chunkSize, 0);
}
xmlParseChunk(ctxt, NULL, 0, 1);
xmlFuzzCheckFailureReport("xmlParseChunk",
ctxt->errNo == XML_ERR_NO_MEMORY,
ctxt->errNo == XML_IO_EIO);
xmlFreeDoc(ctxt->myDoc);
xmlFreeParserCtxt(ctxt);
}
}
#endif
exit:
xmlFuzzInjectFailure(0);
xmlFuzzDataCleanup();
xmlResetLastError();
return(0);
}
size_t
LLVMFuzzerCustomMutator(char *data, size_t size, size_t maxSize,
unsigned seed) {
static const xmlFuzzChunkDesc chunks[] = {
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* opts */
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* failurePos */
{ 0, 0 }
};
return xmlFuzzMutateChunks(chunks, data, size, maxSize, seed,
LLVMFuzzerMutate);
}
+2
View File
@@ -0,0 +1,2 @@
[libfuzzer]
dict = xml.dict
+105
View File
@@ -0,0 +1,105 @@
/*
* xinclude.c: a libFuzzer target to test the XInclude engine.
*
* See Copyright for the status of this software.
*/
#include <libxml/catalog.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlerror.h>
#include <libxml/xinclude.h>
#include "fuzz.h"
int
LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
char ***argv ATTRIBUTE_UNUSED) {
xmlFuzzMemSetup();
xmlInitParser();
#ifdef LIBXML_CATALOG_ENABLED
xmlInitializeCatalog();
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
return 0;
}
int
LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlParserCtxtPtr ctxt;
xmlDocPtr doc;
const char *docBuffer, *docUrl;
size_t failurePos, docSize;
int opts;
xmlFuzzDataInit(data, size);
opts = (int) xmlFuzzReadInt(4);
opts &= ~XML_PARSE_DTDVALID &
~XML_PARSE_SAX1;
failurePos = xmlFuzzReadInt(4) % (size + 100);
xmlFuzzReadEntities();
docBuffer = xmlFuzzMainEntity(&docSize);
docUrl = xmlFuzzMainUrl();
if (docBuffer == NULL)
goto exit;
/* Pull parser */
xmlFuzzInjectFailure(failurePos);
ctxt = xmlNewParserCtxt();
if (ctxt != NULL) {
xmlXIncludeCtxtPtr xinc;
xmlDocPtr copy;
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL, opts);
xmlFuzzCheckFailureReport("xmlCtxtReadMemory",
doc == NULL && ctxt->errNo == XML_ERR_NO_MEMORY,
doc == NULL && ctxt->errNo == XML_IO_EIO);
xinc = xmlXIncludeNewContext(doc);
xmlXIncludeSetResourceLoader(xinc, xmlFuzzResourceLoader, NULL);
xmlXIncludeSetFlags(xinc, opts);
xmlXIncludeProcessNode(xinc, (xmlNodePtr) doc);
if (doc != NULL) {
xmlFuzzCheckFailureReport("xmlXIncludeProcessNode",
xinc == NULL ||
xmlXIncludeGetLastError(xinc) == XML_ERR_NO_MEMORY,
xinc != NULL &&
xmlXIncludeGetLastError(xinc) == XML_IO_EIO);
}
xmlXIncludeFreeContext(xinc);
xmlFuzzResetFailure();
copy = xmlCopyDoc(doc, 1);
if (doc != NULL)
xmlFuzzCheckFailureReport("xmlCopyNode", copy == NULL, 0);
xmlFreeDoc(copy);
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctxt);
}
exit:
xmlFuzzInjectFailure(0);
xmlFuzzDataCleanup();
xmlResetLastError();
return(0);
}
size_t
LLVMFuzzerCustomMutator(char *data, size_t size, size_t maxSize,
unsigned seed) {
static const xmlFuzzChunkDesc chunks[] = {
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* opts */
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* failurePos */
{ 0, 0 }
};
return xmlFuzzMutateChunks(chunks, data, size, maxSize, seed,
LLVMFuzzerMutate);
}
+2
View File
@@ -0,0 +1,2 @@
[libfuzzer]
dict = lint.dict
+263
View File
@@ -0,0 +1,263 @@
/*
* xml.c: a libFuzzer target to test several XML parser interfaces.
*
* See Copyright for the status of this software.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libxml/catalog.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlerror.h>
#include <libxml/xmlsave.h>
#include "fuzz.h"
int
LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
char ***argv ATTRIBUTE_UNUSED) {
xmlFuzzMemSetup();
xmlInitParser();
#ifdef LIBXML_CATALOG_ENABLED
xmlInitializeCatalog();
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
return 0;
}
int
LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlParserCtxtPtr ctxt;
xmlDocPtr doc;
const char *docBuffer, *docUrl;
size_t failurePos, docSize, maxChunkSize;
int opts;
int errorCode;
#ifdef LIBXML_OUTPUT_ENABLED
xmlBufferPtr outbuf = NULL;
const char *saveEncoding;
int saveOpts;
#endif
xmlFuzzDataInit(data, size);
opts = (int) xmlFuzzReadInt(4);
/*
* Disable options that are known to cause timeouts
*/
opts &= ~XML_PARSE_DTDVALID &
~XML_PARSE_SAX1;
failurePos = xmlFuzzReadInt(4) % (size + 100);
maxChunkSize = xmlFuzzReadInt(4) % (size + size / 8 + 1);
if (maxChunkSize == 0)
maxChunkSize = 1;
#ifdef LIBXML_OUTPUT_ENABLED
/* TODO: Take from fuzz data */
saveOpts = 0;
saveEncoding = NULL;
#endif
xmlFuzzReadEntities();
docBuffer = xmlFuzzMainEntity(&docSize);
docUrl = xmlFuzzMainUrl();
if (docBuffer == NULL)
goto exit;
/* Pull parser */
xmlFuzzInjectFailure(failurePos);
ctxt = xmlNewParserCtxt();
if (ctxt == NULL) {
errorCode = XML_ERR_NO_MEMORY;
} else {
xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
doc = xmlCtxtReadMemory(ctxt, docBuffer, docSize, docUrl, NULL, opts);
errorCode = ctxt->errNo;
xmlFuzzCheckFailureReport("xmlCtxtReadMemory",
doc == NULL && errorCode == XML_ERR_NO_MEMORY,
doc == NULL && errorCode == XML_IO_EIO);
if (doc != NULL) {
#ifdef LIBXML_OUTPUT_ENABLED
xmlSaveCtxtPtr save;
outbuf = xmlBufferCreate();
/* Also test the serializer. */
save = xmlSaveToBuffer(outbuf, saveEncoding, saveOpts);
if (save == NULL) {
xmlBufferFree(outbuf);
outbuf = NULL;
} else {
int saveErr;
xmlSaveDoc(save, doc);
saveErr = xmlSaveFinish(save);
xmlFuzzCheckFailureReport("xmlSaveToBuffer",
saveErr == XML_ERR_NO_MEMORY,
saveErr == XML_IO_EIO);
if (saveErr != XML_ERR_OK) {
xmlBufferFree(outbuf);
outbuf = NULL;
}
}
#endif
xmlFreeDoc(doc);
}
xmlFreeParserCtxt(ctxt);
}
/* Push parser */
#ifdef LIBXML_PUSH_ENABLED
xmlFuzzInjectFailure(failurePos);
/*
* FIXME: xmlCreatePushParserCtxt can still report OOM errors
* to stderr.
*/
xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, docUrl);
xmlSetGenericErrorFunc(NULL, NULL);
if (ctxt != NULL) {
size_t consumed;
int errorCodePush, numChunks, maxChunks;
xmlCtxtSetErrorHandler(ctxt, xmlFuzzSErrorFunc, NULL);
xmlCtxtSetResourceLoader(ctxt, xmlFuzzResourceLoader, NULL);
xmlCtxtUseOptions(ctxt, opts);
consumed = 0;
numChunks = 0;
maxChunks = 50 + docSize / 100;
while (numChunks == 0 ||
(consumed < docSize && numChunks < maxChunks)) {
size_t chunkSize;
int terminate;
numChunks += 1;
chunkSize = docSize - consumed;
if (numChunks < maxChunks && chunkSize > maxChunkSize) {
chunkSize = maxChunkSize;
terminate = 0;
} else {
terminate = 1;
}
xmlParseChunk(ctxt, docBuffer + consumed, chunkSize, terminate);
consumed += chunkSize;
}
errorCodePush = ctxt->errNo;
xmlFuzzCheckFailureReport("xmlParseChunk",
errorCodePush == XML_ERR_NO_MEMORY,
errorCodePush == XML_IO_EIO);
doc = ctxt->myDoc;
/*
* Push and pull parser differ in when exactly they
* stop parsing, and the error code is the *last* error
* reported, so we can't check whether the codes match.
*/
if (errorCode != XML_ERR_NO_MEMORY &&
errorCode != XML_IO_EIO &&
errorCodePush != XML_ERR_NO_MEMORY &&
errorCodePush != XML_IO_EIO &&
(errorCode == XML_ERR_OK) != (errorCodePush == XML_ERR_OK)) {
fprintf(stderr, "pull/push parser error mismatch: %d != %d\n",
errorCode, errorCodePush);
#if 0
FILE *f = fopen("c.xml", "wb");
fwrite(docBuffer, docSize, 1, f);
fclose(f);
#endif
abort();
}
#ifdef LIBXML_OUTPUT_ENABLED
/*
* Verify that pull and push parser produce the same result.
*
* The NOBLANKS option doesn't work reliably in push mode.
*/
if ((opts & XML_PARSE_NOBLANKS) == 0 &&
errorCode == XML_ERR_OK &&
errorCodePush == XML_ERR_OK &&
outbuf != NULL) {
xmlBufferPtr outbufPush;
xmlSaveCtxtPtr save;
outbufPush = xmlBufferCreate();
save = xmlSaveToBuffer(outbufPush, saveEncoding, saveOpts);
if (save != NULL) {
int saveErr;
xmlSaveDoc(save, doc);
saveErr = xmlSaveFinish(save);
if (saveErr == XML_ERR_OK) {
int outbufSize = xmlBufferLength(outbuf);
if (outbufSize != xmlBufferLength(outbufPush) ||
memcmp(xmlBufferContent(outbuf),
xmlBufferContent(outbufPush),
outbufSize) != 0) {
fprintf(stderr, "pull/push parser roundtrip "
"mismatch\n");
#if 0
FILE *f = fopen("c.xml", "wb");
fwrite(docBuffer, docSize, 1, f);
fclose(f);
fprintf(stderr, "opts: %X\n", opts);
fprintf(stderr, "---\n%s\n---\n%s\n---\n",
xmlBufferContent(outbuf),
xmlBufferContent(outbufPush));
#endif
abort();
}
}
}
xmlBufferFree(outbufPush);
}
#endif
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctxt);
}
#endif
exit:
#ifdef LIBXML_OUTPUT_ENABLED
xmlBufferFree(outbuf);
#endif
xmlFuzzInjectFailure(0);
xmlFuzzDataCleanup();
xmlResetLastError();
return(0);
}
size_t
LLVMFuzzerCustomMutator(char *data, size_t size, size_t maxSize,
unsigned seed) {
static const xmlFuzzChunkDesc chunks[] = {
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* opts */
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* failurePos */
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* maxChunkSize */
{ 0, 0 }
};
return xmlFuzzMutateChunks(chunks, data, size, maxSize, seed,
LLVMFuzzerMutate);
}
+121
View File
@@ -0,0 +1,121 @@
xml_decl="<?xml version='1.0'?>"
xml_decl_standalone="<?xml version='1.0' standalone='1'?>"
xml_decl_latin1="<?xml version='1.0' encoding='ISO-8859-1'?>"
elem_start_end="<a></a>"
elem_empty="<a/>"
elem_ns_start_end="<a:a xmlns:a='a'></a:a>"
elem_ns_empty="<a:a xmlns:a='a'/>"
attr=" a='a'"
ns_decl=" xmlns:a='a'"
ns_default=" xmlns='a'"
ns_prefix="a:"
cdata_section="<![CDATA[ ]]>"
comment="<!-- -->"
pi="<?a?>"
doctype="<!DOCTYPE a []>"
doctype_system="<!DOCTYPE a SYSTEM 'a' []>"
doctype_system="<!DOCTYPE a PUBLIC 'a' 'a' []>"
elem_decl_any="<!ELEMENT a ANY>"
elem_decl_empty="<!ELEMENT a EMPTY>"
elem_decl_children="<!ELEMENT a (a)>"
elem_decl_mixed="<!ELEMENT a (#PCDATA|a)>"
elem_children_choice="|a"
elem_children_seq=",a"
elem_children_sub_choice="|(a)"
elem_children_sub_seq=",(a)"
elem_quant_any="*"
elem_quant_opt="?"
elem_quant_some="+"
attr_decl_cdata_req="<!ATTLIST a a CDATA #REQUIRED>"
attr_decl_cdata_imp="<!ATTLIST a a CDATA #IMPLIED>"
attr_decl_cdata_def="<!ATTLIST a a CDATA 'a'>"
attr_decl_cdata_fix="<!ATTLIST a a CDATA #FIXED 'a'>"
attr_decl_id_imp="<!ATTLIST a a ID #IMPLIED>"
attr_decl_id_req="<!ATTLIST a a ID #REQUIRED>"
attr_decl_id_def="<!ATTLIST a a ID 'a'>"
attr_decl_id_fix="<!ATTLIST a a ID #FIXED 'a'>"
attr_decl_idref_imp="<!ATTLIST a a IDREF #IMPLIED>"
attr_decl_idref_req="<!ATTLIST a a IDREF #REQUIRED>"
attr_decl_idref_def="<!ATTLIST a a IDREF 'a'>"
attr_decl_idref_fix="<!ATTLIST a a IDREF #FIXED 'a'>"
attr_decl_idrefs_imp="<!ATTLIST a a IDREFS #IMPLIED>"
attr_decl_idrefs_req="<!ATTLIST a a IDREFS #REQUIRED>"
attr_decl_idrefs_def="<!ATTLIST a a IDREFS 'a'>"
attr_decl_idrefs_fix="<!ATTLIST a a IDREFS #FIXED 'a'>"
attr_decl_entity_imp="<!ATTLIST a a ENTITY #IMPLIED>"
attr_decl_entity_req="<!ATTLIST a a ENTITY #REQUIRED>"
attr_decl_entity_def="<!ATTLIST a a ENTITY 'a'>"
attr_decl_entity_fix="<!ATTLIST a a ENTITY #FIXED 'a'>"
attr_decl_entities_imp="<!ATTLIST a a ENTITIES #IMPLIED>"
attr_decl_entities_req="<!ATTLIST a a ENTITIES #REQUIRED>"
attr_decl_entities_def="<!ATTLIST a a ENTITIES 'a'>"
attr_decl_entities_fix="<!ATTLIST a a ENTITIES #FIXED 'a'>"
attr_decl_nmtoken_imp="<!ATTLIST a a NMTOKEN #IMPLIED>"
attr_decl_nmtoken_req="<!ATTLIST a a NMTOKEN #REQUIRED>"
attr_decl_nmtoken_def="<!ATTLIST a a NMTOKEN 'a'>"
attr_decl_nmtoken_fix="<!ATTLIST a a NMTOKEN #FIXED 'a'>"
attr_decl_nmtokens_imp="<!ATTLIST a a NMTOKENS #IMPLIED>"
attr_decl_nmtokens_req="<!ATTLIST a a NMTOKENS #REQUIRED>"
attr_decl_nmtokens_def="<!ATTLIST a a NMTOKENS 'a'>"
attr_decl_nmtokens_fix="<!ATTLIST a a NMTOKENS #FIXED 'a'>"
attr_decl_enum_imp="<!ATTLIST a a (a) #IMPLIED>"
attr_decl_enum_req="<!ATTLIST a a (a) #REQUIRED>"
attr_decl_enum_def="<!ATTLIST a a (a) 'a'>"
attr_decl_enum_fix="<!ATTLIST a a (a) #FIXED 'a'>"
attr_decl_notation_imp="<!ATTLIST a a NOTATION (a) #IMPLIED>"
attr_decl_notation_req="<!ATTLIST a a NOTATION (a) #REQUIRED>"
attr_decl_notation_def="<!ATTLIST a a NOTATION (a) 'a'>"
attr_decl_notation_fix="<!ATTLIST a a NOTATION (a) #FIXED 'a'>"
include_sect="<![INCLUDE[ ]]>"
ignore_sect="<![IGNORE[ ]]>"
ge_decl="<!ENTITY a 'a'>"
ge_decl_system="<!ENTITY a SYSTEM 'a'>"
ge_decl_system_ndata="<!ENTITY a SYSTEM 'a' NDATA a>"
ge_decl_public="<!ENTITY a PUBLIC 'a' 'a'>"
ge_decl_public_ndata="<!ENTITY a PUBLIC 'a' 'a' NDATA a>"
pe_decl="<!ENTITY % a 'a'>"
pe_decl_system="<!ENTITY % a SYSTEM 'a'>"
pe_decl_public="<!ENTITY % a PUBLIC 'a' 'a'>"
char_ref_dec="&#60;"
char_ref_hex="&#x3c;"
char_ref_quoted="&#38;#60;"
ge_ref_lt="&lt;"
ge_ref_gt="&gt;"
ge_ref_amp="&amp;"
ge_ref_apos="&apos;"
ge_ref_quot="&quot;"
ge_ref="&a;"
ge_ref_quoted="&#38;a;"
pe_ref="%a;"
pe_ref_quoted="&#37;a;"
notation_decl_public="<!NOTATION a PUBLIC 'a'>"
notation_decl_system="<!NOTATION a SYSTEM 'a'>"
cs_utf8="UTF-8"
cs_utf16="UTF-16"
cs_utf16le="UTF-16LE"
cs_utf16be="UTF-16BE"
cs_ucs2="UCS-2"
cs_ucs4="UCS-4"
cs_latin1="ISO-8859-1"
cs_ascii="ASCII"
cs_ebcdic="EBCDIC"
cs_iso2022jp="ISO-2022-JP"
cs_shift_jis="SHIFT_JIS"
cs_euc_jp="EUC-JP"
+86
View File
@@ -0,0 +1,86 @@
/*
* xpath.c: a libFuzzer target to test XPath and XPointer expressions.
*
* See Copyright for the status of this software.
*/
#include <libxml/catalog.h>
#include <libxml/parser.h>
#include <libxml/xpointer.h>
#include "fuzz.h"
int
LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
char ***argv ATTRIBUTE_UNUSED) {
xmlFuzzMemSetup();
xmlInitParser();
#ifdef LIBXML_CATALOG_ENABLED
xmlInitializeCatalog();
xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
#endif
xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
return 0;
}
int
LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlDocPtr doc;
const char *expr, *xml;
size_t failurePos, exprSize, xmlSize;
if (size > 10000)
return(0);
xmlFuzzDataInit(data, size);
failurePos = xmlFuzzReadInt(4) % (size + 100);
expr = xmlFuzzReadString(&exprSize);
xml = xmlFuzzReadString(&xmlSize);
/* Recovery mode allows more input to be fuzzed. */
doc = xmlReadMemory(xml, xmlSize, NULL, NULL, XML_PARSE_RECOVER);
if (doc != NULL) {
xmlXPathContextPtr xpctxt;
xmlFuzzInjectFailure(failurePos);
xpctxt = xmlXPathNewContext(doc);
if (xpctxt != NULL) {
int res;
/* Operation limit to avoid timeout */
xpctxt->opLimit = 500000;
res = xmlXPathContextSetCache(xpctxt, 1, 4, 0);
xmlFuzzCheckFailureReport("xmlXPathContextSetCache", res == -1, 0);
xmlFuzzResetFailure();
xmlXPathFreeObject(xmlXPtrEval(BAD_CAST expr, xpctxt));
xmlFuzzCheckFailureReport("xmlXPtrEval",
xpctxt->lastError.code == XML_ERR_NO_MEMORY, 0);
xmlXPathFreeContext(xpctxt);
}
xmlFuzzInjectFailure(0);
xmlFreeDoc(doc);
}
xmlFuzzDataCleanup();
xmlResetLastError();
return(0);
}
size_t
LLVMFuzzerCustomMutator(char *data, size_t size, size_t maxSize,
unsigned seed) {
static const xmlFuzzChunkDesc chunks[] = {
{ 4, XML_FUZZ_PROB_ONE / 10 }, /* failurePos */
{ 0, 0 }
};
return xmlFuzzMutateChunks(chunks, data, size, maxSize, seed,
LLVMFuzzerMutate);
}
+94
View File
@@ -0,0 +1,94 @@
# XML
elem_a="<a></a>"
elem_b="<b></b>"
elem_c="<c></c>"
elem_d="<d></d>"
elem_empty="<a/>"
elem_ns_a="<a:a xmlns:a='a'></a:a>"
elem_ns_b="<b:b xmlns:b='b'></b:b>"
attr_a=" a='a'"
attr_b=" b='b'"
ns_decl=" xmlns:a='a'"
ns_default=" xmlns='a'"
ns_prefix_a="a:"
ns_prefix_b="b:"
cdata_section="<![CDATA[ ]]>"
comment="<!-- -->"
pi="<?a?>"
# XPath
axis_ancestor="ancestor::"
axis_ancestor_or_self="ancestor-or-self::"
axis_attribute="attribute::"
axis_attribute_abbrev="@"
axis_child="child::"
axis_descendant="descendant::"
axis_descendant_or_self="descendant-or-self::"
axis_following="following::"
axis_following_sibling="following-sibling::"
axis_namespace="namespace::"
axis_parent="parent::"
axis_preceding="preceding::"
axis_preceding_siblings="preceding-sibling::"
axis_self="self::"
node_test_ns="a:"
val_num="=(1.0)"
val_str_sq="=('a')"
val_str_dq="=(\"a\")"
val_node_set="=(*)"
val_elem="=(b)"
step_root="/"
step_descendant="//"
step_any="//*"
step_any_l="*//"
step_elem="//b"
step_ns_elem="//a:a"
step_comment="//comment()"
step_node="//node()"
step_node_l="node()//"
step_pi="//processing-instruction()"
step_text="//text()"
step_parent="../"
op_plus="+1"
op_minus=" - 1"
op_neg="-"
op_mul="*1"
op_div=" div 1"
op_mod=" mod 1"
op_and=" and 1"
op_or=" or 1"
op_ne="!=1"
op_lt="<1"
op_gt=">1"
op_le="<=1"
op_ge=">=1"
op_predicate_num="[1]"
op_predicate_last="[last()]"
op_predicate_str="['a']"
op_predicate="[1=1]"
op_arg_num=",1"
op_arg_str=",'a'"
op_arg_node=",*"
op_union="|//b"
var_num="=$f"
var_bool="=$b"
var_str="=$s"
var_node_set="=$n"
# Unicode
utf8_2="\xC3\x84"
utf8_3="\xE2\x80\x9C"
utf8_4="\xF0\x9F\x98\x80"