Skip to content

Verifier: size the size-prefixed identifier gate from the actual read window - #9235

Open
esoalba wants to merge 2 commits into
google:masterfrom
esoalba:fix/verifier-sizeprefixed-identifier-gate
Open

Verifier: size the size-prefixed identifier gate from the actual read window#9235
esoalba wants to merge 2 commits into
google:masterfrom
esoalba:fix/verifier-sizeprefixed-identifier-gate

Conversation

@esoalba

@esoalba esoalba commented Sep 9, 2026

Copy link
Copy Markdown

Verifier: size the size-prefixed identifier gate from the actual read window

What this changes

One gate in include/flatbuffers/verifier.h, inside
VerifierTemplate::VerifyBufferFromStart, from

size_ >= 2 * sizeof(flatbuffers::uoffset_t)

to

size_ >= start + sizeof(flatbuffers::uoffset_t) + kFileIdentifierLength

which is exactly the read window BufferHasIdentifier(buf_ + start,
identifier) touches: [start + sizeof(uoffset_t),
start + sizeof(uoffset_t) + kFileIdentifierLength).

Why

VerifySizePrefixedBuffer<T, uoffset64_t>(identifier) reaches this gate
with start = sizeof(uoffset64_t) = 8. The old bound is a constant that
only covers the start == 0 layout, so a 12-15 byte attacker-supplied
size-prefixed buffer passes every size check and the identifier scan in
BufferHasIdentifier (buffer.h, strncmp) reads up to 4 bytes past the end
of the buffer.

This is reachable from generated code: flatc emits exactly this call for
any schema with an (offset64) field plus a file_identifier (see
src/idl_gen_cpp.cpp, the size-prefixed root verifier), so the shape is in
normal end-to-end use. The existing 64-bit test schema declares no
file_identifier, which is why its generated verifier passes a null
identifier and never exercises this branch.

Verification (local ASAN builds, clang and gcc)

  • 64-bit size-prefixed reproducer (12-15 bytes, non-null identifier):
    previously an AddressSanitizer heap-buffer-overflow read; with the
    patch it returns false cleanly, no ASAN report.
  • Legal 12-byte 32-bit size-prefixed buffer (identifier at [8, 12)):
    still verifies — no over-rejection on the classic path.
  • Valid 20-byte non-prefixed buffer: unchanged.

Test note

An in-tree regression test would fit tests/64bit/, but the current
test_64bit.fbs has no file_identifier, and adding one triggers
regeneration of test_64bit_generated.h plus the committed .bin/.afb
fixtures — a larger blast radius I left as a maintainer decision. Happy
to add it as a follow-up if wanted; the reproducer above is
self-contained.

… window

The identifier check in VerifyBufferFromStart guards the read with
size_ >= 2 * sizeof(uoffset_t), which only covers the start == 0 layout.
For size-prefixed 64-bit buffers (SizeT = uoffset64_t, start = 8) the
identifier read sits at [12, 16); a 12-15 byte buffer passes the gate
and BufferHasIdentifier reads up to 4 bytes past the end.

Key the gate on the actual read window:
size_ >= start + sizeof(uoffset_t) + kFileIdentifierLength.

Behavior is unchanged for 32-bit paths and rejects before reading for
the 64-bit size-prefixed shape.
@google-cla

google-cla Bot commented Sep 9, 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 the c++ label Sep 9, 2026
@esoalba

esoalba commented Sep 9, 2026

Copy link
Copy Markdown
Author

CLA signed (esoalba) — please re-run the cla/google check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant