diff --git a/include/flatbuffers/verifier.h b/include/flatbuffers/verifier.h index a0b793597c..6341250fa8 100644 --- a/include/flatbuffers/verifier.h +++ b/include/flatbuffers/verifier.h @@ -204,11 +204,17 @@ class VerifierTemplate FLATBUFFERS_FINAL_CLASS { // Buffers have to be of some size to be valid. The reason it is a runtime // check instead of static_assert, is that nested flatbuffers go through // this call and their size is determined at runtime. - if (!Check(size_ >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false; + if (!Check(size_ >= start && + size_ - start >= FLATBUFFERS_MIN_BUFFER_SIZE)) { + return false; + } // If an identifier is provided, check that we have a buffer - if (identifier && !Check((size_ >= 2 * sizeof(flatbuffers::uoffset_t) && - BufferHasIdentifier(buf_ + start, identifier)))) { + if (identifier && + !Check((size_ >= start && + size_ - start >= sizeof(flatbuffers::uoffset_t) + + flatbuffers::kFileIdentifierLength && + BufferHasIdentifier(buf_ + start, identifier)))) { return false; } @@ -257,7 +263,7 @@ class VerifierTemplate FLATBUFFERS_FINAL_CLASS { return Verify(0U) && // Ensure the prefixed size is within the bounds of the provided // length. - Check(ReadScalar(buf_) + sizeof(SizeT) <= size_) && + Check(ReadScalar(buf_) <= size_ - sizeof(SizeT)) && VerifyBufferFromStart(identifier, sizeof(SizeT)); } diff --git a/tests/test.cpp b/tests/test.cpp index 5a43546f53..8a4f29c167 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1290,6 +1290,25 @@ void NestedVerifierTest() { } } +struct AlwaysValidRoot { + bool Verify(flatbuffers::Verifier&) const { return true; } +}; + +void SizePrefixedLengthOverflowTest() { + // Craft a 64-bit size-prefixed buffer whose length field overflows when + // adding sizeof(SizeT), which must not be accepted. + const uint8_t crafted[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // size prefix + 0x01, 0x00, 0x00, 0x00, // non-zero root offset + }; + + flatbuffers::Verifier verifier(crafted, sizeof(crafted)); + const bool verified = + verifier.VerifySizePrefixedBuffer(nullptr); + TEST_EQ(verified, false); +} + void SizeVerifierTest() { // Create a monster. flatbuffers::FlatBufferBuilder builder; @@ -1849,6 +1868,7 @@ int FlatBufferTests(const std::string& tests_data_path) { FlatbuffersIteratorsTest(); WarningsAsErrorsTest(); NestedVerifierTest(); + SizePrefixedLengthOverflowTest(); SizeVerifierTest(); PrivateAnnotationsLeaks(); JsonUnsortedArrayTest();