Describe the issue
An attacker may corrupt memory if he is able to trigger an allocation of a big prevector while memory is low. When either a new prevector is created or an existing one is resized, change_capacity is called:
void change_capacity(size_type new_capacity) {
if (new_capacity <= N) {
... // code omitted
}
} else {
if (!is_direct()) {
/* FIXME: Because malloc/realloc here won't call new_handler if allocation fails, assert
success. These should instead use an allocator or new/delete so that handlers
are called as necessary, but performance would be slightly degraded by doing so. */
_union.indirect = static_cast<char*>(realloc(_union.indirect, ((size_t)sizeof(T)) * new_capacity));
assert(_union.indirect);
_union.capacity = new_capacity;
} else {
char* new_indirect = static_cast<char*>(malloc(((size_t)sizeof(T)) * new_capacity));
assert(new_indirect);
T* src = direct_ptr(0);
T* dst = reinterpret_cast<T*>(new_indirect);
memcpy(dst, src, size() * sizeof(T));
_union.indirect = new_indirect;
_union.capacity = new_capacity;
_size += N + 1;
}
}
}
If either realloc or malloc above fail for some reason, e.g., due to out of memory, in Release builds the capacity would still be increased even though no memory was allocated, so any arbitrary data written to the prevector would overwrite unrelated memory.
Can you reliably reproduce the issue?
I haven't exploited this yet. Since the serialize module uses prevector, it looks like a good attack vector: get the victim to serialize or deserialize a big piece of data, when memory is very low (either just because that's the system's state or because the attacker drained the memory somehow).
Even if this isn't currently exploitable, since this is an infrastructure which might become exploitable through future uses, it should be fixed quickly.
Expected behaviour
An exception should be thrown if memory fails to allocate, as already mentioned in the inline FIXME comment in the code.
What version of bitcoin-core are you using?
commit 7fd49d01dc2ea444ba4d81d0cfa17486b03c8515