1cc68614dSXin LI /*
2cc68614dSXin LI * Copyright (C) 2016 The Android Open Source Project
3cc68614dSXin LI *
4cc68614dSXin LI * Licensed under the Apache License, Version 2.0 (the "License");
5cc68614dSXin LI * you may not use this file except in compliance with the License.
6cc68614dSXin LI * You may obtain a copy of the License at
7cc68614dSXin LI *
8cc68614dSXin LI * http://www.apache.org/licenses/LICENSE-2.0
9cc68614dSXin LI *
10cc68614dSXin LI * Unless required by applicable law or agreed to in writing, software
11cc68614dSXin LI * distributed under the License is distributed on an "AS IS" BASIS,
12cc68614dSXin LI * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cc68614dSXin LI * See the License for the specific language governing permissions and
14cc68614dSXin LI * limitations under the License.
15cc68614dSXin LI */
16cc68614dSXin LI
17cc68614dSXin LI #include <assert.h>
18cc68614dSXin LI #include <stdint.h>
19cc68614dSXin LI #include <string.h>
20cc68614dSXin LI
21cc68614dSXin LI #include "expat.h"
22cc68614dSXin LI #include "siphash.h"
23cc68614dSXin LI
24cc68614dSXin LI // Macros to convert preprocessor macros to string literals. See
25cc68614dSXin LI // https://gcc.gnu.org/onlinedocs/gcc-3.4.3/cpp/Stringification.html
26cc68614dSXin LI #define xstr(s) str(s)
27cc68614dSXin LI #define str(s) #s
28cc68614dSXin LI
29cc68614dSXin LI // The encoder type that we wish to fuzz should come from the compile-time
30cc68614dSXin LI // definition `ENCODING_FOR_FUZZING`. This allows us to have a separate fuzzer
31cc68614dSXin LI // binary for
32cc68614dSXin LI #ifndef ENCODING_FOR_FUZZING
33cc68614dSXin LI # error "ENCODING_FOR_FUZZING was not provided to this fuzz target."
34cc68614dSXin LI #endif
35cc68614dSXin LI
36cc68614dSXin LI // 16-byte deterministic hash key.
37cc68614dSXin LI static unsigned char hash_key[16] = "FUZZING IS FUN!";
38cc68614dSXin LI
39cc68614dSXin LI static void XMLCALL
start(void * userData,const XML_Char * name,const XML_Char ** atts)40cc68614dSXin LI start(void *userData, const XML_Char *name, const XML_Char **atts) {
41cc68614dSXin LI (void)userData;
42cc68614dSXin LI (void)name;
43cc68614dSXin LI (void)atts;
44cc68614dSXin LI }
45cc68614dSXin LI static void XMLCALL
end(void * userData,const XML_Char * name)46cc68614dSXin LI end(void *userData, const XML_Char *name) {
47cc68614dSXin LI (void)userData;
48cc68614dSXin LI (void)name;
49cc68614dSXin LI }
50cc68614dSXin LI
51*4543ef51SXin LI static void XMLCALL
may_stop_character_handler(void * userData,const XML_Char * s,int len)52*4543ef51SXin LI may_stop_character_handler(void *userData, const XML_Char *s, int len) {
53*4543ef51SXin LI XML_Parser parser = (XML_Parser)userData;
54*4543ef51SXin LI if (len > 1 && s[0] == 's') {
55*4543ef51SXin LI XML_StopParser(parser, s[1] == 'r' ? XML_FALSE : XML_TRUE);
56*4543ef51SXin LI }
57*4543ef51SXin LI }
58*4543ef51SXin LI
59*4543ef51SXin LI static void
ParseOneInput(XML_Parser p,const uint8_t * data,size_t size)60*4543ef51SXin LI ParseOneInput(XML_Parser p, const uint8_t *data, size_t size) {
61*4543ef51SXin LI // Set the hash salt using siphash to generate a deterministic hash.
62*4543ef51SXin LI struct sipkey *key = sip_keyof(hash_key);
63*4543ef51SXin LI XML_SetHashSalt(p, (unsigned long)siphash24(data, size, key));
64*4543ef51SXin LI (void)sip24_valid;
65*4543ef51SXin LI
66*4543ef51SXin LI XML_SetUserData(p, p);
67*4543ef51SXin LI XML_SetElementHandler(p, start, end);
68*4543ef51SXin LI XML_SetCharacterDataHandler(p, may_stop_character_handler);
69*4543ef51SXin LI void *buf = XML_GetBuffer(p, size);
70*4543ef51SXin LI assert(buf);
71*4543ef51SXin LI memcpy(buf, data, size);
72*4543ef51SXin LI XML_ParseBuffer(p, size, 0);
73*4543ef51SXin LI buf = XML_GetBuffer(p, size);
74*4543ef51SXin LI if (buf == NULL) {
75*4543ef51SXin LI return;
76*4543ef51SXin LI }
77*4543ef51SXin LI memcpy(buf, data, size);
78*4543ef51SXin LI if (XML_ParseBuffer(p, size, 1) == XML_STATUS_ERROR) {
79*4543ef51SXin LI XML_ErrorString(XML_GetErrorCode(p));
80*4543ef51SXin LI }
81*4543ef51SXin LI XML_GetCurrentLineNumber(p);
82*4543ef51SXin LI if (size % 2) {
83*4543ef51SXin LI XML_ParserReset(p, NULL);
84*4543ef51SXin LI }
85*4543ef51SXin LI }
86*4543ef51SXin LI
87cc68614dSXin LI int
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)88cc68614dSXin LI LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
89cc68614dSXin LI if (size == 0)
90cc68614dSXin LI return 0;
91cc68614dSXin LI
92*4543ef51SXin LI XML_Parser parentParser = XML_ParserCreate(xstr(ENCODING_FOR_FUZZING));
93*4543ef51SXin LI assert(parentParser);
94*4543ef51SXin LI ParseOneInput(parentParser, data, size);
95*4543ef51SXin LI // not freed yet, but used later and freed then
96cc68614dSXin LI
97*4543ef51SXin LI XML_Parser namespaceParser = XML_ParserCreateNS(NULL, '!');
98*4543ef51SXin LI assert(namespaceParser);
99*4543ef51SXin LI ParseOneInput(namespaceParser, data, size);
100*4543ef51SXin LI XML_ParserFree(namespaceParser);
101cc68614dSXin LI
102*4543ef51SXin LI XML_Parser externalEntityParser
103*4543ef51SXin LI = XML_ExternalEntityParserCreate(parentParser, "e1", NULL);
104*4543ef51SXin LI assert(externalEntityParser);
105*4543ef51SXin LI ParseOneInput(externalEntityParser, data, size);
106*4543ef51SXin LI XML_ParserFree(externalEntityParser);
107cc68614dSXin LI
108*4543ef51SXin LI XML_Parser externalDtdParser
109*4543ef51SXin LI = XML_ExternalEntityParserCreate(parentParser, NULL, NULL);
110*4543ef51SXin LI assert(externalDtdParser);
111*4543ef51SXin LI ParseOneInput(externalDtdParser, data, size);
112*4543ef51SXin LI XML_ParserFree(externalDtdParser);
113*4543ef51SXin LI
114*4543ef51SXin LI // finally frees this parser which served as parent
115*4543ef51SXin LI XML_ParserFree(parentParser);
116cc68614dSXin LI return 0;
117cc68614dSXin LI }
118