Repository navigation
[verifier] Do not form out-of-bounds pointers for vector elements - #9463
Open
The-Peacemaker wants to merge 1 commit into
Open
The-Peacemaker wants to merge 1 commit into
The-Peacemaker wants to merge 1 commit into
Conversation
VerifyVectorOfStrings and VerifyVectorOfTables resolved each element through Vector::Get, whose IndirectHelper forms a pointer from the element offset before any bounds check. The verifier's own contract says a pointer must be proven inside the buffer before it is formed. For a crafted buffer that means the verifier materialises a pointer pointing (in the worst case) gigabytes past the end of the buffer before rejecting it. Behaviour today is safe in release (rejection still happens), but the invariant is meant to hold even on rejection paths; UBSan builds that instrument pointer arithmetic will flag this, and any future accessor that touches the element before the final check would turn it into a real read.
This branch has not been deployed
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.
The verifier's own contract is that a pointer is only ever formed once it is known to be inside the buffer.
VerifyOffsetalready enforces this by checking the target arithmetically first.VerifyVectorOfStringsandVerifyVectorOfTablesdid not follow the same discipline. Both resolved each element withvec->Get(i), whoseIndirectHelperforms a pointer straight from the element offset before any bounds check. For a crafted buffer the verifier therefore materialises a pointer pointing arbitrarily far outside the buffer before rejecting it.Nothing dereferences the result today, so release behaviour is unchanged, but the invariant is meant to hold even on rejection paths, and it is exactly the kind of thing UBSan builds that instrument pointer arithmetic will trip over (and that a future accessor reaching the element first would turn into a real read). This makes the vector paths obey the same rule
VerifyOffsetalready applies everywhere else.What this does
Adds
VerifyVectorElement, which validates a vector element's offset with the existingVerifyOffset<uoffset_t>(which does not form a pointer until the target is proven in bounds) and returns the resolved pointer, or nullptr when the element is out of range.VerifyVectorOfStringsandVerifyVectorOfTablesnow go through it instead ofvec->Get(i).The 32-bit offset is correct for these two functions: both take
Vector<Offset<T>>, whose element/offset type isuoffset_t. The 64-bitVector64/Offset64uses a different type and does not bind to these.Tests
Adds
VerifyVectorElementBoundsTest(tests/test.cpp), covering valid buffers verifying and string/table vector elements corrupted to0xFFFFFFFFbeing rejected.Behaviour
No behavioural change for well-formed buffers: same buffers verify. Corrupt offsets still fail verification, now without forming an out-of-bounds pointer on the way.