aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerek Bailey <derekbailey@google.com>2022-08-14 12:40:57 -0700
committerGitHub <noreply@github.com>2022-08-14 12:40:57 -0700
commit44a7dc99953fadae9d27902af507273b584d90fe (patch)
tree0d9ee5c28f1ce8f8dee59c7a0fb5be2b7e8a0637
parent3cc2daa78f6d8ea7edfd64482626b3549df1339d (diff)
downloadflatbuffers-44a7dc99953fadae9d27902af507273b584d90fe.tar.gz
Define minimum buffer size (#7440)
* add check for zero sized buffers * Define minimum flatbuffer size
-rw-r--r--include/flatbuffers/base.h7
-rw-r--r--include/flatbuffers/verifier.h11
-rw-r--r--tests/test.cpp22
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() {