reflection: bounds-check the union type slot in the verifier#9122
reflection: bounds-check the union type slot in the verifier#9122evilgensec wants to merge 2 commits into
Conversation
VerifyVector reads the union type-vector slot at vec_field.offset() - sizeof(voffset_t) via GetPointer with no VerifyField, while the value-vector slot is verified. flatbuffers::Verify can therefore dereference an out-of-range vtable offset on a malformed buffer. Add the same VerifyField the value path uses before reading the type vector.
VerifyObject's union branch read the union type byte via GetField<uint8_t> at offset() - sizeof(voffset_t) with no VerifyField, the same gap fixed for the union type vector in VerifyVector. A union value field sorts before its hidden type field, so the verifier reaches the unvalidated type slot first, and a poisoned vtable offset caused an out-of-bounds read. Guard it the same way the value field is guarded. Add a reflection_test.cpp regression test that builds a malformed buffer for both a vector of unions and a scalar union and checks Verify rejects each instead of reading out of bounds.
|
@dbaileychess this is ready when you have a moment.
The change adds the missing |
Problem
reflection::Verifyis the runtime verifier for untrusted reflection-encoded FlatBuffers. When it verifies a union it reads the union type slot from the vtable without bounds-checking the voffset first, unlike the sibling value slot and every other field:VerifyVector(vector of unions) reads the type vector atvec_field.offset() - sizeof(voffset_t)viaGetPointerwith noVerifyField(4-byte read, up to ~64 KB past the buffer).VerifyObject(scalar union) reads the type byte atfield_def->offset() - sizeof(voffset_t)viaGetField<uint8_t>with noVerifyField(1-byte read).A union value field sorts before its hidden type field, so the verifier reaches the unvalidated type slot first. A malformed buffer with a poisoned type voffset makes
Verifyread out of bounds. Both confirmed with ASAN.Fix
Add the missing
VerifyFieldguard in both branches, matching the existing value-slot and string-field checks. Add areflection_test.cppregression test that builds a schema plus a malformed buffer for the vector-of-unions and scalar-union cases and checksVerifyrejects each instead of reading out of bounds.