Skip to content

fix: add bounds checking before GetFieldT in reflection VerifyObject#9101

Open
Ashutosh0x wants to merge 1 commit into
google:masterfrom
Ashutosh0x:fix/reflection-verify-heap-overflow
Open

fix: add bounds checking before GetFieldT in reflection VerifyObject#9101
Ashutosh0x wants to merge 1 commit into
google:masterfrom
Ashutosh0x:fix/reflection-verify-heap-overflow

Conversation

@Ashutosh0x
Copy link
Copy Markdown

Fixes #9040

Summary

Heap buffer overflow in flatbuffers::Verify() via the reflection verification path. The VerifyObject function calls GetFieldT() for Obj and Union field types without first verifying that the field offset points within the buffer. A malformed table with out-of-bounds field offsets causes GetFieldT -> Table::GetPointer -> ReadScalar<uoffset_t> to read past the allocated buffer boundary.

Root Cause

VerifyObject in reflection.cpp verifies scalar fields (Bool, Byte, Int, etc.) with table->VerifyField<T>() before accessing them, but the Obj (line 243) and Union (line 255) cases call GetFieldT() directly, skipping the bounds check:

// BEFORE: No bounds check before GetFieldT
case reflection::Obj: {
    // ...
    if (!VerifyObject(v, schema, *child_obj,
                      flatbuffers::GetFieldT(*table, *field_def),  // OOB read here
                      field_def->required())) {

GetFieldT does table.GetPointer<Table*>(field.offset()), which reads a uoffset_t from the table buffer. If the vtable entry points past the end of the buffer, this is an out-of-bounds read.

Fix

Added VerifyField<uoffset_t> calls before each GetFieldT call in VerifyObject, matching the pattern already used for String fields (line 226):

// AFTER: Bounds check before GetFieldT
case reflection::Obj: {
    // ...
    if (!table->VerifyField<uoffset_t>(v, field_def->offset(),
                                       sizeof(uoffset_t)))
      return false;
    if (!VerifyObject(v, schema, *child_obj,
                      flatbuffers::GetFieldT(*table, *field_def),  // Now safe
                      field_def->required())) {

Impact

Aspect Details
Type Heap-buffer-overflow (CWE-125: Out-of-bounds Read)
Severity High
Attack Vector Malformed FlatBuffers reflection schemas
Affected Component src/reflection.cpp VerifyObject
Affected Functions Verify(), VerifySizePrefixed()

ASAN Trace (from #9040)

READ of size 4 at 0x511000000448 thread T0
    #0 flatbuffers::ReadScalar<unsigned int>(void const*)
    #1 flatbuffers::Table::GetPointer<flatbuffers::Table*>(unsigned short) const
    #4 flatbuffers::Verify(...) reflection.cpp:790
0x511000000448 is located 789 bytes after 243-byte region [0x511000000040,0x511000000133)
SUMMARY: AddressSanitizer: heap-buffer-overflow

Add VerifyField<uoffset_t> checks before GetFieldT calls in
VerifyObject for Obj and Union field types. Without these checks,
a malformed table with out-of-bounds field offsets causes GetFieldT
to compute a pointer outside the buffer, leading to heap-buffer-
overflow in ReadScalar during reflection verification.

Fixes google#9040
@Ashutosh0x Ashutosh0x requested a review from dbaileychess as a code owner May 26, 2026 08:01
@github-actions github-actions Bot added c++ codegen Involving generating code from schema labels May 26, 2026
@Ashutosh0x
Copy link
Copy Markdown
Author

Hi @dbaileychess — Requesting review on this security fix. It adds Verifier::VerifyField() bounds checking before GetFieldT() calls in reflection VerifyObject to prevent out-of-bounds heap reads from crafted FlatBuffer binaries. Ready for review. Thanks!

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.

Heap Buffer Overflow in FlatBuffers Reflection Verifier

1 participant