Skip to content

Fix heap-buffer-overflow in ForAllFields for out-of-range field id - #9195

Open
prasanna8585 wants to merge 1 commit into
google:masterfrom
prasanna8585:fix/forallfields-out-of-range-id-oob-write
Open

Fix heap-buffer-overflow in ForAllFields for out-of-range field id#9195
prasanna8585 wants to merge 1 commit into
google:masterfrom
prasanna8585:fix/forallfields-out-of-range-id-oob-write

Conversation

@prasanna8585

@prasanna8585 prasanna8585 commented Aug 6, 2026

Copy link
Copy Markdown

Summary

reflection::ForAllFields() (src/reflection.cpp) resizes a std::vector<uint32_t> to the object's real field count, then writes to it using each field's raw, schema-supplied id (uint16_t, up to 65535) as the index -- with no bounds check:

std::vector<uint32_t> field_to_id_map;
field_to_id_map.resize(object->fields()->size());
for (uint32_t i = 0; i < object->fields()->size(); ++i) {
  auto field = object->fields()->Get(i);
  field_to_id_map[field->id()] = i;   // field->id() unchecked
}

This is the exact same bug class already fixed in StructDef::Deserialize (idl_parser.cpp, #8988) -- resize a vector to field count, then index into it with a raw, schema-supplied field ID -- but that fix never touched this sibling function.

Reachable via flatc --nim, flatc --lua, and flatc --annotate, all of which call ForAllFields directly on a caller-supplied .bfbs reflection schema file.

Verification

Confirmed via AddressSanitizer against the real, unmodified, compiled library, using a reflection::Object built through the library's own real builder API:

==ERROR: AddressSanitizer: heap-buffer-overflow on address ...
WRITE of size 4 at ... thread T0
    #0 ... in flatbuffers::ForAllFields(...) src/reflection.cpp:387
0x... is located 196 bytes after 4-byte region [...]
allocated by thread T0 here:
    ...
    #6 ... in flatbuffers::ForAllFields(...) src/reflection.cpp:382
SUMMARY: AddressSanitizer: heap-buffer-overflow src/reflection.cpp:387 in flatbuffers::ForAllFields(...)

(A 1-field object with field->id() = 50 overflows by exactly 50*4 - 4 = 196 bytes -- confirming the write offset is directly attacker-controlled via the field's id.)

Fix

Skip any field whose id is out of range, rather than writing OOB. ForAllFields is void with no error-return mechanism (unlike StructDef::Deserialize, which can return false), so this is the minimal, non-breaking fix -- matching the validation StructDef::Deserialize already applies to this same untrusted data.

Testing

  • Added ForAllFieldsOutOfRangeIdTest alongside the existing ForAllFieldsReverseTest, exercising the exact crafted-schema attack input.
  • Full official CMake build, ASan-instrumented, full flattests suite: ALL TESTS PASSED, zero regressions across the entire codebase.
  • Re-verified the attack input is silently skipped (not visited, not crashing) and that normal in-range field IDs are still visited correctly and in the right order after the fix.

reflection::ForAllFields() (src/reflection.cpp) resizes a
std::vector<uint32_t> to the object's real field count, then writes to
it using each field's raw, schema-supplied id (uint16_t, up to 65535)
as the index, with no bounds check. This is the same bug class already
fixed in StructDef::Deserialize (idl_parser.cpp, google#8988), but was never
applied here.

Reachable via flatc --nim, flatc --lua, and flatc --annotate, all of
which call ForAllFields directly on a caller-supplied .bfbs reflection
schema file.

Confirmed via AddressSanitizer against the real, unmodified, compiled
library: heap-buffer-overflow WRITE in
field_to_id_map[field->id()] = i, at an attacker-controlled offset
directly proportional to the crafted field id.

Fix: skip any field whose id is out of range rather than writing OOB.
ForAllFields is void with no error-return mechanism, so this is the
minimal non-breaking fix, matching the validation
StructDef::Deserialize already applies to this same untrusted data.

Adds a regression test (ForAllFieldsOutOfRangeIdTest) alongside the
existing ForAllFieldsReverseTest. Full official CMake test suite
(flattests), ASan-instrumented: ALL TESTS PASSED, zero regressions.
@github-actions github-actions Bot added c++ codegen Involving generating code from schema labels Aug 6, 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