From eac1c7e2e5afffffddf305a290451d80be4a2c19 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sun, 21 Jun 2020 14:42:00 +0200 Subject: [PATCH] Fuzz target for XML Schemas This only tests the schema parser for now. --- fuzz/.gitignore | 3 +++ fuzz/Makefile.am | 29 +++++++++++++++++++++++- fuzz/fuzz.c | 10 +++++++++ fuzz/fuzz.h | 3 +++ fuzz/schema.c | 36 +++++++++++++++++++++++++++++ fuzz/schema.dict | 55 +++++++++++++++++++++++++++++++++++++++++++++ fuzz/schema.options | 2 ++ fuzz/schemaSeed.c | 34 ++++++++++++++++++++++++++++ fuzz/xmlSeed.c | 1 + 9 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 fuzz/schema.c create mode 100644 fuzz/schema.dict create mode 100644 fuzz/schema.options create mode 100644 fuzz/schemaSeed.c diff --git a/fuzz/.gitignore b/fuzz/.gitignore index 178a6592..d7ea7964 100644 --- a/fuzz/.gitignore +++ b/fuzz/.gitignore @@ -1,7 +1,10 @@ corpus/ html regexp +schema +schemaSeed seed/xml* +seed/schema* testFuzzer uri xml diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am index a286f867..c360e567 100644 --- a/fuzz/Makefile.am +++ b/fuzz/Makefile.am @@ -1,4 +1,4 @@ -EXTRA_PROGRAMS = html regexp uri xml xmlSeed +EXTRA_PROGRAMS = html regexp uri schema schemaSeed xml xmlSeed check_PROGRAMS = testFuzzer CLEANFILES = $(EXTRA_PROGRAMS) AM_CPPFLAGS = -I$(top_srcdir)/include @@ -84,3 +84,30 @@ fuzz-uri: uri$(EXEEXT) -timeout=2 \ corpus/uri $(srcdir)/seed/uri +schemaSeed_SOURCES = schemaSeed.c fuzz.c + +seed/schema.stamp: schemaSeed$(EXEEXT) + @mkdir -p seed/schema + @for i in ../test/schemas/*.xsd; do \ + if [ -f $$i ]; then \ + echo Processing seed $$i; \ + base=$$(basename $$i) \ + outfile=$(abs_builddir)/seed/schema/$$base; \ + pushd $$(dirname $$i) >/dev/null; \ + $(abs_builddir)/schemaSeed$(EXEEXT) $$base > $$outfile; \ + popd >/dev/null; \ + fi; \ + done + @touch seed/schema.stamp + +schema_SOURCES = schema.c fuzz.c +schema_LDFLAGS = -fsanitize=fuzzer + +fuzz-schema: schema$(EXEEXT) seed/schema.stamp + @mkdir -p corpus/schema + ./schema$(EXEEXT) \ + -dict=schema.dict \ + -max_len=$(PARSER_FUZZER_MAX_LEN) \ + -timeout=20 \ + corpus/schema seed/schema + diff --git a/fuzz/fuzz.c b/fuzz/fuzz.c index 5bf8e552..ba7c9cad 100644 --- a/fuzz/fuzz.c +++ b/fuzz/fuzz.c @@ -265,6 +265,16 @@ xmlFuzzReadEntities(void) { } } +/** + * xmlFuzzMainUrl: + * + * Returns the main URL. + */ +const char * +xmlFuzzMainUrl(void) { + return(fuzzData.mainUrl); +} + /** * xmlFuzzMainEntity: * @size: size of the main entity in bytes diff --git a/fuzz/fuzz.h b/fuzz/fuzz.h index eabe0941..7e7fc29c 100644 --- a/fuzz/fuzz.h +++ b/fuzz/fuzz.h @@ -42,6 +42,9 @@ xmlFuzzEntityRecorder(const char *URL, const char *ID, xmlParserCtxtPtr ctxt); void xmlFuzzReadEntities(void); +const char * +xmlFuzzMainUrl(void); + const char * xmlFuzzMainEntity(size_t *size); diff --git a/fuzz/schema.c b/fuzz/schema.c new file mode 100644 index 00000000..f1ee9380 --- /dev/null +++ b/fuzz/schema.c @@ -0,0 +1,36 @@ +/* + * schema.c: a libFuzzer target to test the XML Schema processor. + * + * See Copyright for the status of this software. + */ + +#include +#include "fuzz.h" + +int +LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED, + char ***argv ATTRIBUTE_UNUSED) { + xmlInitParser(); + xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc); + xmlSetExternalEntityLoader(xmlFuzzEntityLoader); + + return 0; +} + +int +LLVMFuzzerTestOneInput(const char *data, size_t size) { + xmlSchemaParserCtxtPtr pctxt; + + xmlFuzzDataInit(data, size); + xmlFuzzReadEntities(); + + pctxt = xmlSchemaNewParserCtxt(xmlFuzzMainUrl()); + xmlSchemaSetParserErrors(pctxt, xmlFuzzErrorFunc, xmlFuzzErrorFunc, NULL); + xmlSchemaFree(xmlSchemaParse(pctxt)); + xmlSchemaFreeParserCtxt(pctxt); + + xmlFuzzDataCleanup(); + + return(0); +} + diff --git a/fuzz/schema.dict b/fuzz/schema.dict new file mode 100644 index 00000000..9a8fd386 --- /dev/null +++ b/fuzz/schema.dict @@ -0,0 +1,55 @@ +# TODO: Add more language elements + +xs_annotation="" + +xs_attribute="" +xs_attribute_required="" +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_restriction_string="" +xs_list="" +xs_union="" + +# Restrictions +xs_min_exclusive="" +xs_min_inclusive="" +xs_max_exclusive="" +xs_max_inclusive="" +xs_total_digits="" +xs_fraction_digits="" +xs_length="" +xs_min_length="" +xs_max_length="" +xs_enumeration="" +xs_white_space_collapse="" +xs_white_space_preserve="" +xs_white_space_replace="" +xs_pattern="" + diff --git a/fuzz/schema.options b/fuzz/schema.options new file mode 100644 index 00000000..09f13d89 --- /dev/null +++ b/fuzz/schema.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 80000 diff --git a/fuzz/schemaSeed.c b/fuzz/schemaSeed.c new file mode 100644 index 00000000..4e2c6bc6 --- /dev/null +++ b/fuzz/schemaSeed.c @@ -0,0 +1,34 @@ +/* + * xmlSeed.c: Generate the XML seed corpus for fuzzing. + * + * See Copyright for the status of this software. + */ + +#include +#include +#include "fuzz.h" + +int +main(int argc, char **argv) { + xmlSchemaPtr schema; + xmlSchemaParserCtxtPtr pctxt; + + if (argc != 2) { + fprintf(stderr, "Usage: schemaSeed [XSD]\n"); + return(1); + } + + xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc); + xmlSetExternalEntityLoader(xmlFuzzEntityRecorder); + + pctxt = xmlSchemaNewParserCtxt(argv[1]); + xmlSchemaSetParserErrors(pctxt, xmlFuzzErrorFunc, xmlFuzzErrorFunc, NULL); + schema = xmlSchemaParse(pctxt); + xmlSchemaFreeParserCtxt(pctxt); + + xmlSchemaFree(schema); + xmlFuzzDataCleanup(); + + return(0); +} + diff --git a/fuzz/xmlSeed.c b/fuzz/xmlSeed.c index fc64cd45..5ce97d0b 100644 --- a/fuzz/xmlSeed.c +++ b/fuzz/xmlSeed.c @@ -13,6 +13,7 @@ main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Usage: xmlSeed [FILE]\n"); + return(1); } fwrite(&opts, sizeof(opts), 1, stdout);