tinyxml2
tinyxml2 copied to clipboard
Possible OOB in XMLUtil::ReadBOM
Hello, I found an out-of-bound error when running the following fuzz driver in OSS-Fuzz.
#include "tinyxml2/tinyxml2.h"
#include <cstdint>
#include <cstdlib>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// Ensure that the data is not null or empty
if (size < 2) {
return 0;
}
// Convert the input data into a const char* to pass to the ReadBOM function
const char *input_data = reinterpret_cast<const char *>(data);
// Create a boolean pointer to pass to ReadBOM
bool result = false;
bool *bom_detected = &result;
// Call the ReadBOM function from tinyxml2 and fuzz it
const char *bom = tinyxml2::XMLUtil::ReadBOM(input_data, bom_detected);
// Further processing can be done here if needed, but in this case, we are only fuzzing
// the ReadBOM function, so there is no specific output to check or validate.
// Return 0 to indicate the fuzzing has completed successfully for this input
return 0;
}
Here is the asan log:
==12==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000019392 at pc 0x564b854b10ed bp 0x7ffd9c56bfa0 sp 0x7ffd9c56bf98
READ of size 1 at 0x502000019392 thread T0
SCARINESS: 12 (1-byte-read-heap-buffer-overflow)
#0 0x564b854b10ec in tinyxml2::XMLUtil::ReadBOM(char const*, bool*) /src/tinyxml2/tinyxml2.cpp:408:16
#1 0x564b854ae8dc in LLVMFuzzerTestOneInput /src/xmltest_tinyxml2_404.cpp:19:23
#2 0x564b85363370 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
#3 0x564b85362b95 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:516:7
#4 0x564b85364375 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:760:19
#5 0x564b85365105 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile>>&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:905:5
#6 0x564b85353f4b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:914:6
#7 0x564b8537f322 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#8 0x7f8d73ae9082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 0702430aef5fa3dda43986563e9ffcc47efbd75e)
#9 0x564b853467cd in _start (/out/xmltest_tinyxml2_404+0x537cd)
SUMMARY: AddressSanitizer: heap-buffer-overflow /src/tinyxml2/tinyxml2.cpp:408:16 in tinyxml2::XMLUtil::ReadBOM(char const*, bool*)
Shadow bytes around the buggy address:
0x502000019100: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa
0x502000019180: fa fa fd fa fa fa fd fa fa fa fd fd fa fa fd fa
0x502000019200: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
0x502000019280: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
0x502000019300: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
=>0x502000019380: fa fa[02]fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000019400: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000019480: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000019500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000019580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000019600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
==12==ABORTING
MS: 4 ChangeBit-CopyPart-ChangeBit-CrossOver-; base unit: 9c81164e10bf612c352dca3ecabf57743b451d42
0xef,0xbb,
\357\273
It seems if p points to a string shorter than 3 bytes (e.g., 1-byte, or 2-byte data), this will read invalid memory addresses.
https://github.com/leethomason/tinyxml2/blob/9148bdf719e997d1f474be6bcc7943881046dba1/tinyxml2.cpp#L399-L410