diff options
author | Derek Bailey <derekbailey@google.com> | 2022-08-14 12:40:57 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-14 12:40:57 -0700 |
commit | 44a7dc99953fadae9d27902af507273b584d90fe (patch) | |
tree | 0d9ee5c28f1ce8f8dee59c7a0fb5be2b7e8a0637 | |
parent | 3cc2daa78f6d8ea7edfd64482626b3549df1339d (diff) | |
download | flatbuffers-44a7dc99953fadae9d27902af507273b584d90fe.tar.gz |
Define minimum buffer size (#7440)
* add check for zero sized buffers
* Define minimum flatbuffer size
-rw-r--r-- | include/flatbuffers/base.h | 7 | ||||
-rw-r--r-- | include/flatbuffers/verifier.h | 11 | ||||
-rw-r--r-- | tests/test.cpp | 22 |
3 files changed, 40 insertions, 0 deletions
diff --git a/include/flatbuffers/base.h b/include/flatbuffers/base.h index bb10db85..57b613f8 100644 --- a/include/flatbuffers/base.h +++ b/include/flatbuffers/base.h @@ -331,6 +331,13 @@ typedef uintmax_t largest_scalar_t; // In 32bits, this evaluates to 2GB - 1 #define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(::flatbuffers::soffset_t) * 8 - 1)) - 1) +// The minimum size buffer that can be a valid flatbuffer. +// Includes the offset to the root table (uoffset_t), the offset to the vtable +// of the root table (soffset_t), the size of the vtable (uint16_t), and the +// size of the referring table (uint16_t). +#define FLATBUFFERS_MIN_BUFFER_SIZE sizeof(uoffset_t) + sizeof(soffset_t) + \ + sizeof(uint16_t) + sizeof(uint16_t) + // We support aligning the contents of buffers up to this size. #ifndef FLATBUFFERS_MAX_ALIGNMENT #define FLATBUFFERS_MAX_ALIGNMENT 32 diff --git a/include/flatbuffers/verifier.h b/include/flatbuffers/verifier.h index dd46dcfa..0241223e 100644 --- a/include/flatbuffers/verifier.h +++ b/include/flatbuffers/verifier.h @@ -178,6 +178,12 @@ class Verifier FLATBUFFERS_FINAL_CLASS { template<typename T> bool VerifyBufferFromStart(const char *const identifier, const size_t start) { + // 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 an identifier is provided, check that we have a buffer if (identifier && !Check((size_ >= 2 * sizeof(flatbuffers::uoffset_t) && BufferHasIdentifier(buf_ + start, identifier)))) { return false; @@ -198,7 +204,12 @@ class Verifier FLATBUFFERS_FINAL_CLASS { template<typename T> bool VerifyNestedFlatBuffer(const Vector<uint8_t> *const buf, const char *const identifier) { + // An empty buffer is OK as it indicates not present. if (!buf) return true; + + // If there is a nested buffer, it must be greater than the min size. + if(!Check(buf->size() >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false; + Verifier nested_verifier(buf->data(), buf->size()); return nested_verifier.VerifyBuffer<T>(identifier); } diff --git a/tests/test.cpp b/tests/test.cpp index e7a906e7..97c808a8 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -4340,6 +4340,28 @@ void NestedVerifierTest() { builder.GetSize()); TEST_EQ(false, VerifyMonsterBuffer(verifier)); } + + { + // Create the outer monster. + flatbuffers::FlatBufferBuilder builder; + + // Purposely invalidate the nested flatbuffer setting its length to 0, an + // invalid length. + uint8_t *invalid_nested_buffer = nullptr; + auto nested_monster_bytes = builder.CreateVector(invalid_nested_buffer, 0); + + auto name = builder.CreateString("OuterMonster"); + + MonsterBuilder mon_builder(builder); + mon_builder.add_name(name); + mon_builder.add_testnestedflatbuffer(nested_monster_bytes); + FinishMonsterBuffer(builder, mon_builder.Finish()); + + // Verify the root monster fails, since the included nested monster fails. + flatbuffers::Verifier verifier(builder.GetBufferPointer(), + builder.GetSize()); + TEST_EQ(false, VerifyMonsterBuffer(verifier)); + } } void ParseIncorrectMonsterJsonTest() { |