xref: /freebsd/contrib/expat/fuzz/xml_parsebuffer_fuzzer.c (revision fe9278888fd4414abe2d922e469cf608005f4c65)
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  *
8*fe927888SPhilip Paeps  *      https://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 
514543ef51SXin LI static void XMLCALL
may_stop_character_handler(void * userData,const XML_Char * s,int len)524543ef51SXin LI may_stop_character_handler(void *userData, const XML_Char *s, int len) {
534543ef51SXin LI   XML_Parser parser = (XML_Parser)userData;
544543ef51SXin LI   if (len > 1 && s[0] == 's') {
554543ef51SXin LI     XML_StopParser(parser, s[1] == 'r' ? XML_FALSE : XML_TRUE);
564543ef51SXin LI   }
574543ef51SXin LI }
584543ef51SXin LI 
594543ef51SXin LI static void
ParseOneInput(XML_Parser p,const uint8_t * data,size_t size)604543ef51SXin LI ParseOneInput(XML_Parser p, const uint8_t *data, size_t size) {
614543ef51SXin LI   // Set the hash salt using siphash to generate a deterministic hash.
624543ef51SXin LI   struct sipkey *key = sip_keyof(hash_key);
634543ef51SXin LI   XML_SetHashSalt(p, (unsigned long)siphash24(data, size, key));
644543ef51SXin LI   (void)sip24_valid;
654543ef51SXin LI 
664543ef51SXin LI   XML_SetUserData(p, p);
674543ef51SXin LI   XML_SetElementHandler(p, start, end);
684543ef51SXin LI   XML_SetCharacterDataHandler(p, may_stop_character_handler);
694543ef51SXin LI   void *buf = XML_GetBuffer(p, size);
704543ef51SXin LI   assert(buf);
714543ef51SXin LI   memcpy(buf, data, size);
724543ef51SXin LI   XML_ParseBuffer(p, size, 0);
734543ef51SXin LI   buf = XML_GetBuffer(p, size);
744543ef51SXin LI   if (buf == NULL) {
754543ef51SXin LI     return;
764543ef51SXin LI   }
774543ef51SXin LI   memcpy(buf, data, size);
784543ef51SXin LI   if (XML_ParseBuffer(p, size, 1) == XML_STATUS_ERROR) {
794543ef51SXin LI     XML_ErrorString(XML_GetErrorCode(p));
804543ef51SXin LI   }
814543ef51SXin LI   XML_GetCurrentLineNumber(p);
824543ef51SXin LI   if (size % 2) {
834543ef51SXin LI     XML_ParserReset(p, NULL);
844543ef51SXin LI   }
854543ef51SXin LI }
864543ef51SXin 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 
924543ef51SXin LI   XML_Parser parentParser = XML_ParserCreate(xstr(ENCODING_FOR_FUZZING));
934543ef51SXin LI   assert(parentParser);
944543ef51SXin LI   ParseOneInput(parentParser, data, size);
954543ef51SXin LI   // not freed yet, but used later and freed then
96cc68614dSXin LI 
974543ef51SXin LI   XML_Parser namespaceParser = XML_ParserCreateNS(NULL, '!');
984543ef51SXin LI   assert(namespaceParser);
994543ef51SXin LI   ParseOneInput(namespaceParser, data, size);
1004543ef51SXin LI   XML_ParserFree(namespaceParser);
101cc68614dSXin LI 
1024543ef51SXin LI   XML_Parser externalEntityParser
1034543ef51SXin LI       = XML_ExternalEntityParserCreate(parentParser, "e1", NULL);
1044543ef51SXin LI   assert(externalEntityParser);
1054543ef51SXin LI   ParseOneInput(externalEntityParser, data, size);
1064543ef51SXin LI   XML_ParserFree(externalEntityParser);
107cc68614dSXin LI 
1084543ef51SXin LI   XML_Parser externalDtdParser
1094543ef51SXin LI       = XML_ExternalEntityParserCreate(parentParser, NULL, NULL);
1104543ef51SXin LI   assert(externalDtdParser);
1114543ef51SXin LI   ParseOneInput(externalDtdParser, data, size);
1124543ef51SXin LI   XML_ParserFree(externalDtdParser);
1134543ef51SXin LI 
1144543ef51SXin LI   // finally frees this parser which served as parent
1154543ef51SXin LI   XML_ParserFree(parentParser);
116cc68614dSXin LI   return 0;
117cc68614dSXin LI }
118