Skip to content

Integer overflow in msgpack_unpacker_expand_buffer() causes false-success undersized reservation #1181

Description

@mtholmquist

msgpack_unpacker_reserve_buffer(mpac, size) can return true while the buffer has far less than size bytes free.

In msgpack_unpacker_expand_buffer() (src/unpack.c:444-462), the loop target size + mpac->used wraps size_t when size is near SIZE_MAX. The doubling loop exits at the pre-wrap starting value, realloc() succeeds at that small size, and the function returns true unconditionally — no post-condition check.

Reproducer (64-bit, tag c-7.0.1):

msgpack_unpacker mpac;
msgpack_unpacker_init(&mpac, 8);

size_t request = SIZE_MAX - 2;
bool ok = msgpack_unpacker_reserve_buffer(&mpac, request);
// ok == true

size_t actual = msgpack_unpacker_buffer_capacity(&mpac);
// actual == 12  (vs. requested ~1.8e19)

A caller trusting the true return and writing up to the requested size overflows the heap buffer. ASan confirms heap-buffer-overflow WRITE at the memcpy into msgpack_unpacker_buffer(). A Release build (-O2 -DNDEBUG) hits glibc's double free or corruption (out) on the same path.

The library's own example/lib_buffer_unpack.c teaches the exact reserve-then-write pattern, with a defensive assert(buffer_capacity >= request) that compiles away under NDEBUG.

This is the same doubling-loop overflow shape that PRs #547/#550 (2017), #733 (2018), and #776/#792 (2019) fixed in sibling functions. expand_buffer() was not included in any of those fixes.

Suggested fix: check size > SIZE_MAX - mpac->used before the addition, or add a post-condition check (next_size - mpac->used >= size) before returning true.

Confirmed on c-7.0.1 (commit 1be50ee) and c_master HEAD.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions