summaryrefslogtreecommitdiff
path: root/tests/fuzz/xslt.c
blob: 0520550d4240da2e09a7fdc90a0010132d55cf8f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * xslt.c: libFuzzer target for XSLT stylesheets
 *
 * See Copyright for the status of this software.
 *
 * This is a rather naive fuzz target using a static XML document.
 *
 * TODO
 *
 * - Improve seed corpus
 * - Mutate multiple input documents: source, xsl:import, xsl:include
 * - format-number() with xsl:decimal-format
 * - Better coverage for xsl:key and key() function
 * - EXSLT func:function
 * - xsl:document
 */

#include <libgen.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxslt/security.h>
#include <libxslt/transform.h>
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/xsltutils.h>
#include <libexslt/exslt.h>

static xmlDocPtr doc;
static xsltSecurityPrefsPtr sec;

static void
errorFunc(void *ctx, const char *msg, ...) {
    /* Discard error messages. */
}

int
LLVMFuzzerInitialize(int *argc_p ATTRIBUTE_UNUSED,
                     char ***argv_p ATTRIBUTE_UNUSED) {
    const char *xmlFilename = "xslt.xml";
    const char *dir;
    char *argv0;
    char *xmlPath;

    /* Init libraries */
    xmlInitParser();
    xmlXPathInit();
    xsltInit();
    exsltRegisterAll();

    /* Load XML document */
    argv0 = strdup((*argv_p)[0]);
    dir = dirname(argv0);
    xmlPath = malloc(strlen(dir) + 1 + strlen(xmlFilename) + 1);
    sprintf(xmlPath, "%s/%s", dir, xmlFilename);
    doc = xmlReadFile(xmlPath, NULL, 0);
    free(xmlPath);
    free(argv0);
    if (doc == NULL) {
        fprintf(stderr, "Error: unable to parse file \"%s\"\n", xmlPath);
        return -1;
    }

    /* Suppress error messages */
    xmlSetGenericErrorFunc(NULL, errorFunc);
    xsltSetGenericErrorFunc(NULL, errorFunc);

    /* Disallow I/O */
    sec = xsltNewSecurityPrefs();
    xsltSetSecurityPrefs(sec, XSLT_SECPREF_READ_FILE, xsltSecurityForbid);
    xsltSetSecurityPrefs(sec, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid);
    xsltSetSecurityPrefs(sec, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid);
    xsltSetSecurityPrefs(sec, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid);
    xsltSetSecurityPrefs(sec, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid);

    return 0;
}

static void
xsltSetXPathResourceLimits(xmlXPathContextPtr ctxt) {
    ctxt->maxParserDepth = 15;
    ctxt->maxDepth = 100;
    ctxt->opLimit = 100000;
}

int
LLVMFuzzerTestOneInput(const char *data, size_t size) {
    xmlDocPtr xsltDoc;
    xmlDocPtr result;
    xmlNodePtr xsltRoot;
    xsltStylesheetPtr sheet;
    xsltTransformContextPtr ctxt;

    xsltDoc = xmlReadMemory(data, size, NULL, NULL, 0);
    if (xsltDoc == NULL)
        return 0;
    xsltRoot = xmlDocGetRootElement(xsltDoc);
    xmlNewNs(xsltRoot, EXSLT_COMMON_NAMESPACE, BAD_CAST "exsl");
    xmlNewNs(xsltRoot, EXSLT_COMMON_NAMESPACE, BAD_CAST "exslt");
    xmlNewNs(xsltRoot, EXSLT_CRYPTO_NAMESPACE, BAD_CAST "crypto");
    xmlNewNs(xsltRoot, EXSLT_DATE_NAMESPACE, BAD_CAST "date");
    xmlNewNs(xsltRoot, EXSLT_DYNAMIC_NAMESPACE, BAD_CAST "dyn");
    xmlNewNs(xsltRoot, EXSLT_MATH_NAMESPACE, BAD_CAST "math");
    xmlNewNs(xsltRoot, EXSLT_SETS_NAMESPACE, BAD_CAST "set");
    xmlNewNs(xsltRoot, EXSLT_STRINGS_NAMESPACE, BAD_CAST "str");
    xmlNewNs(xsltRoot, SAXON_NAMESPACE, BAD_CAST "saxon");

    sheet = xsltNewStylesheet();
    if (sheet == NULL) {
        xmlFreeDoc(xsltDoc);
        return 0;
    }
    xsltSetXPathResourceLimits(sheet->xpathCtxt);
    sheet->xpathCtxt->opCount = 0;
    if (xsltParseStylesheetUser(sheet, xsltDoc) != 0) {
        xsltFreeStylesheet(sheet);
        xmlFreeDoc(xsltDoc);
        return 0;
    }

    ctxt = xsltNewTransformContext(sheet, doc);
    xsltSetCtxtSecurityPrefs(sec, ctxt);
    ctxt->maxTemplateDepth = 100;
    xsltSetXPathResourceLimits(ctxt->xpathCtxt);
    ctxt->xpathCtxt->opCount = sheet->xpathCtxt->opCount;

    result = xsltApplyStylesheetUser(sheet, doc, NULL, NULL, NULL, ctxt);

    xmlFreeDoc(result);
    xsltFreeTransformContext(ctxt);
    xsltFreeStylesheet(sheet);

    return 0;
}