Pointer::Create/Set with a large array index allocates unboundedly (resource exhaustion)
Pointer::Create/Set with a large array index allocates unboundedly (resource exhaustion via untrusted JSON Pointer)
Summary
GenericPointer::Create() / Set(), when resolving a token whose array index is
large, extends the array up to that index — Reserve(index + 1) then PushBack
of index + 1 - size null values. A JSON Pointer such as /6626666666 (array
index ~6.6 billion) therefore drives a ~37 GB allocation
(MemoryPoolAllocator::Realloc → malloc), exhausting memory.
We want to be upfront: this looks like intended behavior — Create/Set
on a non-existent array index is documented to extend the array to that index.
So the realistic mitigation is caller-side: validate indices in untrusted JSON
Pointers before Set/Create. We are reporting to ask whether you would
consider a guard (or a documentation note), or whether this is by-design.
Detail
/* include/rapidjson/pointer.h — GenericPointer::Create() */
if (v->IsArray()) {
if (t->index >= v->Size()) {
v->Reserve(t->index + 1, allocator); // index 6.6e9 -> Reserve(6.6e9+1)
while (t->index >= v->Size())
v->PushBack(ValueType().Move(), allocator);
...
}
v = &((*v)[t->index]);
}Reserve(6.6e9+1) calls GenericValue::Reserve → MemoryPoolAllocator::Realloc
→ malloc(~37e9) (trace in sanitizer.txt). There is no upper bound because the
extension is intentional.
Reproduction
Minimal standalone using only the public Pointer/Document API (no fuzzer):
#include <rapidjson/document.h>
#include <rapidjson/pointer.h>
int main() {
rapidjson::Document doc; doc.Parse("[]"); // empty array root
rapidjson::Pointer("/6626666666").Create(doc, doc.GetAllocator()); // index 6.6e9
return 0;
}Build: clang++ -O1 -I<rapidjson>/include poc.cpp -o poc, run ./poc.
Create calls Reserve(6626666667) → MemoryPoolAllocator::Realloc → a
~37 GB malloc → OOM. (Verified here: under a constrained address space the
allocation is attempted and fails; the trace malloc(37307189960) ... #12 Pointer::Create pointer.h:480 is in sanitizer.txt.) Aside: on allocation
failure MemoryPoolAllocator does not fail gracefully (it crashes) — but the
primary issue is the unbounded size.
Source: Tencent/rapidjson