Use-after-free in xmlParseContentInternal() when fatal error stops SAX parser
Use-after-free in xmlParseContentInternal() when a fatal error stops SAX parser.
By default, libxml2 does not stop the SAX parser with an error level of XML_ERR_FATAL
, but doing so with a certain input causes a use-after-free in xmlParseContentInternal().
The following ASan crash was reproduced on a19fa11e with a test case that I will upload shortly.
ERROR: AddressSanitizer: heap-use-after-free on address 0x00010aa0014b at pc 0x000106375dec bp 0x00016b6e2ed0 sp 0x00016b6e2ec8
READ of size 1 at 0x00010aa0014b thread T0
#0 0x106375de8 in xmlParseContentInternal parser.c:9808
#1 0x106376770 in xmlParseElement parser.c:9915
#2 0x10638b978 in xmlParseDocument parser.c:10772
#3 0x10471fdec in LLVMFuzzerTestOneInput xml.c:64
#4 0x1047396e4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:611
#5 0x104726778 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) FuzzerDriver.cpp:323
#6 0x10472bda8 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:856
#7 0x104751eec in main FuzzerMain.cpp:20
#8 0x104865088 in start+0x204 (dyld:arm64e+0x5088)
0x00010aa0014b is located 75 bytes inside of 8193-byte region [0x00010aa00100,0x00010aa02101)
freed by thread T0 here:
#0 0x104d66ffc in wrap_free+0x98 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3effc)
#1 0x1062368a4 in xmlBufFree buf.c
#2 0x1065581fc in xmlFreeParserInputBuffer xmlIO.c:2477
#3 0x1063edb00 in xmlHaltParser parserInternals.c:286
#4 0x1063b4d38 in xmlStopParser parser.c:12212
#5 0x106284288 in __xmlRaiseError error.c:666
#6 0x1062b63bc in xmlFatalErr parser.c
#7 0x1062e90d4 in xmlParseCharData parser.c:4449
#8 0x106374510 in xmlParseContentInternal parser.c:9862
#9 0x106376770 in xmlParseElement parser.c:9915
#10 0x10638b978 in xmlParseDocument parser.c:10772
#11 0x10471fdec in LLVMFuzzerTestOneInput xml.c:64
#12 0x1047396e4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:611
#13 0x104726778 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) FuzzerDriver.cpp:323
#14 0x10472bda8 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:856
#15 0x104751eec in main FuzzerMain.cpp:20
#16 0x104865088 in start+0x204 (dyld:arm64e+0x5088)
previously allocated by thread T0 here:
#0 0x104d66ec0 in wrap_malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3eec0)
#1 0x106234aa8 in xmlBufCreateSize buf.c:174
#2 0x106556cd0 in xmlAllocParserInputBuffer xmlIO.c:2332
#3 0x10655daf4 in xmlParserInputBufferCreateMem xmlIO.c:2932
#4 0x10471fcd8 in LLVMFuzzerTestOneInput xml.c:53
#5 0x1047396e4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:611
#6 0x104726778 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) FuzzerDriver.cpp:323
#7 0x10472bda8 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:856
#8 0x104751eec in main FuzzerMain.cpp:20
#9 0x104865088 in start+0x204 (dyld:arm64e+0x5088)
SUMMARY: AddressSanitizer: heap-use-after-free parser.c:9808 in xmlParseContentInternal
Shadow bytes around the buggy address:
0x00702155ffd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x00702155ffe0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x00702155fff0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x007021560000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x007021560010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x007021560020: fd fd fd fd fd fd fd fd fd[fd]fd fd fd fd fd fd
0x007021560030: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x007021560040: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x007021560050: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x007021560060: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x007021560070: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Edited by David Kilzer