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
20cc68614dSXin LI #include "expat.h"
21cc68614dSXin LI #include "siphash.h"
22cc68614dSXin LI
23cc68614dSXin LI // Macros to convert preprocessor macros to string literals. See
24cc68614dSXin LI // https://gcc.gnu.org/onlinedocs/gcc-3.4.3/cpp/Stringification.html
25cc68614dSXin LI #define xstr(s) str(s)
26cc68614dSXin LI #define str(s) #s
27cc68614dSXin LI
28cc68614dSXin LI // The encoder type that we wish to fuzz should come from the compile-time
29cc68614dSXin LI // definition `ENCODING_FOR_FUZZING`. This allows us to have a separate fuzzer
30cc68614dSXin LI // binary for
31cc68614dSXin LI #ifndef ENCODING_FOR_FUZZING
32cc68614dSXin LI # error "ENCODING_FOR_FUZZING was not provided to this fuzz target."
33cc68614dSXin LI #endif
34cc68614dSXin LI
35cc68614dSXin LI // 16-byte deterministic hash key.
36cc68614dSXin LI static unsigned char hash_key[16] = "FUZZING IS FUN!";
37cc68614dSXin LI
38cc68614dSXin LI static void XMLCALL
start(void * userData,const XML_Char * name,const XML_Char ** atts)39cc68614dSXin LI start(void *userData, const XML_Char *name, const XML_Char **atts) {
40cc68614dSXin LI (void)userData;
41cc68614dSXin LI (void)name;
42cc68614dSXin LI (void)atts;
43cc68614dSXin LI }
44cc68614dSXin LI static void XMLCALL
end(void * userData,const XML_Char * name)45cc68614dSXin LI end(void *userData, const XML_Char *name) {
46cc68614dSXin LI (void)userData;
47cc68614dSXin LI (void)name;
48cc68614dSXin LI }
49cc68614dSXin LI
50*4543ef51SXin LI static void XMLCALL
may_stop_character_handler(void * userData,const XML_Char * s,int len)51*4543ef51SXin LI may_stop_character_handler(void *userData, const XML_Char *s, int len) {
52*4543ef51SXin LI XML_Parser parser = (XML_Parser)userData;
53*4543ef51SXin LI if (len > 1 && s[0] == 's') {
54*4543ef51SXin LI XML_StopParser(parser, s[1] == 'r' ? XML_FALSE : XML_TRUE);
55*4543ef51SXin LI }
56*4543ef51SXin LI }
57cc68614dSXin LI
58*4543ef51SXin LI static void
ParseOneInput(XML_Parser p,const uint8_t * data,size_t size)59*4543ef51SXin LI ParseOneInput(XML_Parser p, const uint8_t *data, size_t size) {
60cc68614dSXin LI // Set the hash salt using siphash to generate a deterministic hash.
61cc68614dSXin LI struct sipkey *key = sip_keyof(hash_key);
62cc68614dSXin LI XML_SetHashSalt(p, (unsigned long)siphash24(data, size, key));
63*4543ef51SXin LI (void)sip24_valid;
64cc68614dSXin LI
65*4543ef51SXin LI XML_SetUserData(p, p);
66cc68614dSXin LI XML_SetElementHandler(p, start, end);
67*4543ef51SXin LI XML_SetCharacterDataHandler(p, may_stop_character_handler);
68cc68614dSXin LI XML_Parse(p, (const XML_Char *)data, size, 0);
69*4543ef51SXin LI if (XML_Parse(p, (const XML_Char *)data, size, 1) == XML_STATUS_ERROR) {
70*4543ef51SXin LI XML_ErrorString(XML_GetErrorCode(p));
71*4543ef51SXin LI }
72*4543ef51SXin LI XML_GetCurrentLineNumber(p);
73*4543ef51SXin LI if (size % 2) {
74*4543ef51SXin LI XML_ParserReset(p, NULL);
75*4543ef51SXin LI }
76*4543ef51SXin LI }
77*4543ef51SXin LI
78*4543ef51SXin LI int
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)79*4543ef51SXin LI LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
80*4543ef51SXin LI XML_Parser parentParser = XML_ParserCreate(xstr(ENCODING_FOR_FUZZING));
81*4543ef51SXin LI assert(parentParser);
82*4543ef51SXin LI ParseOneInput(parentParser, data, size);
83*4543ef51SXin LI // not freed yet, but used later and freed then
84*4543ef51SXin LI
85*4543ef51SXin LI XML_Parser namespaceParser = XML_ParserCreateNS(NULL, '!');
86*4543ef51SXin LI assert(namespaceParser);
87*4543ef51SXin LI ParseOneInput(namespaceParser, data, size);
88*4543ef51SXin LI XML_ParserFree(namespaceParser);
89*4543ef51SXin LI
90*4543ef51SXin LI XML_Parser externalEntityParser
91*4543ef51SXin LI = XML_ExternalEntityParserCreate(parentParser, "e1", NULL);
92*4543ef51SXin LI assert(externalEntityParser);
93*4543ef51SXin LI ParseOneInput(externalEntityParser, data, size);
94*4543ef51SXin LI XML_ParserFree(externalEntityParser);
95*4543ef51SXin LI
96*4543ef51SXin LI XML_Parser externalDtdParser
97*4543ef51SXin LI = XML_ExternalEntityParserCreate(parentParser, NULL, NULL);
98*4543ef51SXin LI assert(externalDtdParser);
99*4543ef51SXin LI ParseOneInput(externalDtdParser, data, size);
100*4543ef51SXin LI XML_ParserFree(externalDtdParser);
101*4543ef51SXin LI
102*4543ef51SXin LI // finally frees this parser which served as parent
103*4543ef51SXin LI XML_ParserFree(parentParser);
104cc68614dSXin LI return 0;
105cc68614dSXin LI }
106