Skip to content

reflection: reject out-of-bounds shrink in ResizeContext#9132

Open
foodlook wants to merge 1 commit into
google:masterfrom
foodlook:fix/reflection-resizecontext-oob-shrink
Open

reflection: reject out-of-bounds shrink in ResizeContext#9132
foodlook wants to merge 1 commit into
google:masterfrom
foodlook:fix/reflection-resizecontext-oob-shrink

Conversation

@foodlook

Copy link
Copy Markdown

What

ResizeContext (in src/reflection.cpp) shrinks a buffer with

buf_.erase(buf_.begin() + start + delta_, buf_.begin() + start);

When start + delta_ is negative, the first iterator points before begin()
and std::vector::erase memmoves the trailing elements to a destination before
the allocation — a heap out-of-bounds write.

How it's reached

The public reflection helper SetString() sets start = str_start + 4 and
delta = new_len - old_len. A string longer than its own byte offset + 4 + the
replacement length underflows on shrink. The buffer does not need to be
malformed — a normal buffer that passes flatbuffers::Verify() (e.g. one
dominated by a large string near the front) triggers it when an application
edits it in place with SetString(schema, "x", big_string, &buf).

Fix

Bounds-check the resize range before rewriting any offsets, so an out-of-range
request is rejected without partially mutating the buffer. The check must
precede Straddle()/ResizeTable(), which would otherwise already have
rewritten every offset by delta_ and left the buffer inconsistent.

Legitimate grow/shrink edits are unaffected — the ResizeAnyVector path
computes start at the end of the vector, so its start + delta is always
>= 0.

Tests

Adds ResizeContextShrinkBoundsTest (in tests/reflection_test.cpp, registered
in tests/reflection_test.h, called from tests/test.cpp). Built with
-DFLATBUFFERS_CODE_SANITIZE=ON, the test aborts with an AddressSanitizer heap
out-of-bounds on the current code and passes with this change; it also asserts
that a normal vector shrink still works. flattests is green with the fix
(ALL TESTS PASSED).

ResizeContext shrinks a buffer with

    buf_.erase(buf_.begin() + start + delta_, buf_.begin() + start);

When delta_ is negative (shrinking) and start + delta_ < 0, the first
iterator points before begin(); std::vector::erase then memmoves the
trailing elements to a destination before the allocation, an out-of-bounds
heap write (CWE-787).

This is reachable from the public reflection helper SetString(): it sets
start = str_start + 4 and delta = new_len - old_len, so a string whose length
exceeds its own byte offset + 4 + the replacement length underflows. A buffer
that passes flatbuffers::Verify() is sufficient to trigger it, e.g. shrinking
a large string that sits near the front of the buffer.

Add a bounds check before any offset rewriting so an out-of-range request is
rejected and the buffer is left untouched, instead of corrupting the heap.
Legitimate grow/shrink edits are unaffected (the vector resize path keeps
working; its erase range start + delta is always >= 0).

Adds ResizeContextShrinkBoundsTest, which under AddressSanitizer aborts on the
unpatched code and passes with this fix, and also checks that a normal vector
shrink still succeeds.
@foodlook foodlook requested a review from dbaileychess as a code owner June 11, 2026 06:38
@google-cla

google-cla Bot commented Jun 11, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@github-actions github-actions Bot added c++ codegen Involving generating code from schema labels Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ codegen Involving generating code from schema

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant