[libxml2] Fuzz target for XML Schemas



commit eac1c7e2e5afffffddf305a290451d80be4a2c19
Author: Nick Wellnhofer <wellnhofer aevum de>
Date:   Sun Jun 21 14:42:00 2020 +0200

    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(-)
---
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 <libxml/xmlschemas.h>
+#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: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'/>"
+
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 <stdio.h>
+#include <libxml/xmlschemas.h>
+#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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]