Reject out-of-range reflection Type.index values during verification#9107
Open
huynhtrungcsc wants to merge 1 commit into
Open
Reject out-of-range reflection Type.index values during verification#9107huynhtrungcsc wants to merge 1 commit into
huynhtrungcsc wants to merge 1 commit into
Conversation
The reflection verifier uses Type.index() to look up referenced Objects and Enums in the runtime schema. Invalid negative or out-of-range indexes can otherwise reach Vector::Get() unchecked. Add file-local checked helpers for verifier object/enum lookups and return false on invalid indexes. Add a regression test that mutates an existing BFBS Type.index value out of range, verifies the BFBS remains structurally valid, and confirms the reflection verifier rejects it cleanly. No public API or header changes.
|
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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reject out-of-range reflection Type.index values during verification
Summary
flatbuffers::Verify(const reflection::Schema& schema, const reflection::Object& root_table, const uint8_t* buf, size_t len, ...)usesreflection::Type::index()to look up the referencedreflection::Objectorreflection::Enumfromschema.objects()/schema.enums(). Four verifier-reachable call sites insrc/reflection.cppperform this lookup without bounds-checking the index:VerifyUnion:schema.enums()->Get(union_field.type()->index())VerifyUnion:schema.objects()->Get(elem_type->index())(union element)VerifyVector:schema.objects()->Get(vec_field.type()->index())VerifyObject:schema.objects()->Get(field_def->type()->index())flatbuffers::Vector::Get(uoffset_t i)does not bounds-checki, andreflection::Type::index()returns a signedint32_twith a default of-1when the field is absent. A schema buffer can be structurally well-formed and passreflection::VerifySchemaBuffer(...)while still carrying semantically out-of-rangeType.indexvalues. When such a schema is then passed to the data verifier, the unchecked lookup reads past the end of the objects/enums vector and the subsequent dereference (e.g.child_obj->is_struct()) walks off mapped memory.This PR adds two
static inlinehelpers in the anonymous namespace ofsrc/reflection.cpp:Each helper returns
nullptrif the corresponding vector is null, the index is negative, or the index is past the end of the vector. The four verifier-reachable sites are rerouted through these helpers and returnfalsecleanly onnullptr. The defensive style mirrors the existingGetObjectByIndex/GetEnumByIndexhelpers insrc/bfbs_gen.h(lines 169–188).There are no public API or public header changes. The helpers are file-local; no symbol is exported.
Test
Added
ReflectionTypeIndexBoundsTestintests/reflection_test.cpp(prototype intests/reflection_test.h, registered alongsideReflectionTestandForAllFieldsReverseTestintests/test.cpp).The test:
tests/monster_test.bfbsinto a mutable byte buffer and assertsreflection::VerifySchemaBuffer(...)accepts it.tests/monsterdata_test.monand assertsflatbuffers::Verify(schema, *schema.root_table(), data, size)returnstruefor the unmodified pair.MyGame.Example.Monsterand itsposfield (confirmedreflection::Obj).reflection::Type::VT_INDEXscalar of theposfield in place tostatic_cast<int32_t>(schema.objects()->size() + 100)viaTable::GetAddressOf(VT_INDEX)+flatbuffers::WriteScalar<int32_t>— exactly 4 bytes, no offset rewriting.reflection::VerifySchemaBuffer(...)(structurally valid).flatbuffers::Verify(...)now returnsfalsewith the patch applied.flatbuffers::Verify(...)returnstrueagain, demonstrating the rejection is precise to the malformed input.No new test fixtures are added; only the existing
monster_test.bfbsandmonsterdata_test.monare reused.Negative control. Keeping the regression test in place but reverting
src/reflection.cppto its pre-patch state causesflatteststo terminate withSIGSEGV(process exit code 139,ctestreports***Exception: SegFault). Restoringsrc/reflection.cppto its patched state causes the full suite, includingReflectionTypeIndexBoundsTest, to pass cleanly.Validation
Observed results:
flattestspassed 1/1 (100% tests passed, 0 tests failed out of 1, total time ~0.18s).git diff --checkreturned clean (exit 0, no whitespace or merge-marker errors).Diffstat (4 files only, no build outputs): +123 / −4.
Scope
This PR is intentionally narrow:
Type.index()lookups inVerifyUnion,VerifyVector, andVerifyObject. These are the only sites reachable through the publicflatbuffers::Verify(schema, root_table, buf, len, ...)entry point.Type.index()uses inCopyTable,GetAnyValueS,ResizeContext::ResizeTable, andGetUnionType. Those paths have different threat models (they operate on inputs already trusted to match the schema and are not part of the verifier surface) and changing them would require API-level consideration. They can be addressed in a follow-up if maintainers prefer.Type.indexthat is non-negative and within the corresponding vector, the helpers degenerate tovector->Get(index)— identical to the prior code. The full pre-existing test suite continues to pass.