From 9afed3602c64eadcb2ffaf2c7ce1272b67da080d Mon Sep 17 00:00:00 2001 From: Sharad Boni Date: Wed, 15 Apr 2026 15:40:45 -0700 Subject: [PATCH] Fix reflection verifier: add missing VerifyField calls and length checks The reflection-based VerifyObject() was missing VerifyField calls for Obj (non-struct table) and Union field types before calling GetFieldT(). All other field types (scalars, strings, vectors) already had proper VerifyField checks. Without these checks, a crafted buffer could cause GetFieldT to follow an unvalidated offset, leading to an out-of-bounds read. Additionally, Verify() and VerifySizePrefixed() called GetAnyRoot() / GetAnySizePrefixedRoot() before the Verifier had a chance to validate the buffer. If the buffer was shorter than sizeof(uoffset_t), this would read out of bounds. Add minimum length checks before dereferencing the root offset. --- src/reflection.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/reflection.cpp b/src/reflection.cpp index 268d7d8515..b600d55162 100644 --- a/src/reflection.cpp +++ b/src/reflection.cpp @@ -240,6 +240,9 @@ static bool VerifyObject(flatbuffers::Verifier& v, return false; } } else { + if (!table->VerifyField(v, field_def->offset(), + sizeof(uoffset_t))) + return false; if (!VerifyObject(v, schema, *child_obj, flatbuffers::GetFieldT(*table, *field_def), field_def->required())) { @@ -249,6 +252,9 @@ static bool VerifyObject(flatbuffers::Verifier& v, break; } case reflection::Union: { + if (!table->VerifyField(v, field_def->offset(), + sizeof(uoffset_t))) + return false; // get union type from the prev field voffset_t utype_offset = field_def->offset() - sizeof(voffset_t); auto utype = table->GetField(utype_offset, 0); @@ -786,6 +792,7 @@ Offset CopyTable(FlatBufferBuilder& fbb, bool Verify(const reflection::Schema& schema, const reflection::Object& root, const uint8_t* const buf, const size_t length, const uoffset_t max_depth, const uoffset_t max_tables) { + if (length < sizeof(uoffset_t)) return false; Verifier v(buf, length, max_depth, max_tables); return VerifyObject(v, schema, root, flatbuffers::GetAnyRoot(buf), /*required=*/true); @@ -795,6 +802,7 @@ bool VerifySizePrefixed(const reflection::Schema& schema, const reflection::Object& root, const uint8_t* const buf, const size_t length, const uoffset_t max_depth, const uoffset_t max_tables) { + if (length < sizeof(uoffset_t) * 2) return false; Verifier v(buf, length, max_depth, max_tables); return VerifyObject(v, schema, root, flatbuffers::GetAnySizePrefixedRoot(buf), /*required=*/true);