diff --git a/include/flatbuffers/verifier.h b/include/flatbuffers/verifier.h index 1369e57d8..4ec125293 100644 --- a/include/flatbuffers/verifier.h +++ b/include/flatbuffers/verifier.h @@ -25,15 +25,29 @@ namespace flatbuffers { // Helper class to verify the integrity of a FlatBuffer class Verifier FLATBUFFERS_FINAL_CLASS { public: - Verifier(const uint8_t *const buf, const size_t buf_len, - const uoffset_t _max_depth = 64, - const uoffset_t _max_tables = 1000000, - const bool _check_alignment = true) + struct Options { + // The maximum nesting of tables and vectors before we call it invalid. + uoffset_t max_depth = 64; + // The maximum number of tables we will verify before we call it invalid. + uoffset_t max_tables = 1000000; + // If true, verify all data is aligned. + bool check_alignment = true; + // If true, run verifier on nested flatbuffers + bool check_nested_flatbuffers = true; + + // Manually implemented constructors for compilers that can't figure it out. + Options() = default; + Options(uoffset_t d, uoffset_t t, bool a, bool n) + : max_depth(d), + max_tables(t), + check_alignment(a), + check_nested_flatbuffers(n) {} + }; + + Verifier(const uint8_t *const buf, const size_t buf_len, const Options opts) : buf_(buf), size_(buf_len), - max_depth_(_max_depth), - max_tables_(_max_tables), - check_alignment_(_check_alignment), + opts_(opts), upper_bound_(0), depth_(0), num_tables_(0), @@ -41,6 +55,19 @@ class Verifier FLATBUFFERS_FINAL_CLASS { FLATBUFFERS_ASSERT(size_ < FLATBUFFERS_MAX_BUFFER_SIZE); } + // Deprecated API, please construct with Verifier::Options. + Verifier(const uint8_t *const buf, const size_t buf_len, + const uoffset_t _max_depth = 64, + const uoffset_t _max_tables = 1000000, + const bool _check_alignment = true) + : Verifier(buf, buf_len, + { + _max_depth, + _max_tables, + _check_alignment, + true, + }) {} + // Central location where any verification failures register. bool Check(const bool ok) const { // clang-format off @@ -68,7 +95,7 @@ class Verifier FLATBUFFERS_FINAL_CLASS { } bool VerifyAlignment(const size_t elem, const size_t align) const { - return Check((elem & (align - 1)) == 0 || !check_alignment_); + return Check((elem & (align - 1)) == 0 || !opts_.check_alignment); } // Verify a range indicated by sizeof(T). @@ -204,11 +231,14 @@ class Verifier FLATBUFFERS_FINAL_CLASS { template bool VerifyNestedFlatBuffer(const Vector *const buf, const char *const identifier) { + // Caller opted out of this. + if (!opts_.check_nested_flatbuffers) return true; + // 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; + if (!Check(buf->size() >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false; Verifier nested_verifier(buf->data(), buf->size()); return nested_verifier.VerifyBuffer(identifier); @@ -253,7 +283,7 @@ class Verifier FLATBUFFERS_FINAL_CLASS { bool VerifyComplexity() { depth_++; num_tables_++; - return Check(depth_ <= max_depth_ && num_tables_ <= max_tables_); + return Check(depth_ <= opts_.max_depth && num_tables_ <= opts_.max_tables); } // Called at the end of a table to pop the depth count. @@ -288,9 +318,7 @@ class Verifier FLATBUFFERS_FINAL_CLASS { private: const uint8_t *buf_; const size_t size_; - const uoffset_t max_depth_; - const uoffset_t max_tables_; - const bool check_alignment_; + const Options opts_; mutable size_t upper_bound_; diff --git a/tests/test.cpp b/tests/test.cpp index 842df9854..d99e60650 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1085,6 +1085,14 @@ void NestedVerifierTest() { flatbuffers::Verifier verifier(builder.GetBufferPointer(), builder.GetSize()); TEST_EQ(false, VerifyMonsterBuffer(verifier)); + + // Verify the root monster succeeds, since we've disabled checking nested + // flatbuffers + flatbuffers::Verifier::Options options; + options.check_nested_flatbuffers = false; + flatbuffers::Verifier no_check_nested(builder.GetBufferPointer(), + builder.GetSize(), options); + TEST_EQ(true, VerifyMonsterBuffer(no_check_nested)); } {