diff --git a/include/flatbuffers/flexbuffers.h b/include/flatbuffers/flexbuffers.h index 5c42a7ed47..c29f005ee3 100644 --- a/include/flatbuffers/flexbuffers.h +++ b/include/flatbuffers/flexbuffers.h @@ -1983,8 +1983,10 @@ class Verifier FLATBUFFERS_FINAL_CLASS { #undef FLEX_CHECK_VERIFIED bool VerifyTerminator(const String& s) { - return VerifyFromPointer(reinterpret_cast(s.c_str()), - s.size() + 1); + const uint8_t* p = reinterpret_cast(s.c_str()); + // First make sure the terminator byte is in-buffer, then check it is 0. + // Mirrors the non-flex VerifyString() in verifier.h. + return VerifyFromPointer(p, s.size() + 1) && p[s.size()] == 0; } bool VerifyRef(Reference r) { diff --git a/tests/flexbuffers_test.cpp b/tests/flexbuffers_test.cpp index 6087a0affb..8ea034563e 100644 --- a/tests/flexbuffers_test.cpp +++ b/tests/flexbuffers_test.cpp @@ -314,5 +314,37 @@ void ParseFlexbuffersFromJsonWithNullTest() { } } +// Regression: VerifyBuffer must reject an FBT_STRING whose terminator byte +// is non-zero. Before VerifyTerminator() was hardened to check the +// terminator's *content* (not just its in-buffer position), this passed +// verification and a downstream strlen() on c_str() read OOB. +// +// Layout (1-byte width throughout, total 10 bytes): +// [0] 0x05 size prefix = 5 +// [1..5] 'h','e','l','l','o' string bytes +// [6] 'X' terminator slot — INTENTIONALLY non-zero +// [7] 0x06 root offset: (7) - 6 = byte [1], string data start +// [8] (FBT_STRING<<2)|0 packed_type = FBT_STRING with BIT_WIDTH_8 +// [9] 0x01 root byte_width +void FlexBuffersVerifyStringTerminatorTest() { + const uint8_t buf[] = { + 0x05, + 'h', 'e', 'l', 'l', 'o', + 'X', // non-zero terminator + 0x06, + static_cast((flexbuffers::FBT_STRING << 2) | + flexbuffers::BIT_WIDTH_8), + 0x01, + }; + // Sanity: the buffer parses to an FBT_STRING root of length 5. + auto root = flexbuffers::GetRoot(buf, sizeof(buf)); + TEST_EQ(root.IsString(), true); + TEST_EQ(root.AsString().size(), 5); + // Verifier must reject the buffer because byte [6] is not 0x00. + TEST_EQ(flexbuffers::VerifyBuffer(buf, sizeof(buf), nullptr), false); + std::vector reuse_tracker; + TEST_EQ(flexbuffers::VerifyBuffer(buf, sizeof(buf), &reuse_tracker), false); +} + } // namespace tests } // namespace flatbuffers