xref: /freebsd/contrib/expat/fuzz/xml_parse_fuzzer.c (revision 4543ef516683042d46f3bd3bb8a4f3f746e00499)
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