File indexing completed on 2025-08-27 09:30:29
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef FLATBUFFERS_VERIFIER_H_
0018 #define FLATBUFFERS_VERIFIER_H_
0019
0020 #include "flatbuffers/base.h"
0021 #include "flatbuffers/vector.h"
0022
0023 namespace flatbuffers {
0024
0025
0026 template <bool TrackVerifierBufferSize>
0027 class VerifierTemplate FLATBUFFERS_FINAL_CLASS {
0028 public:
0029 struct Options {
0030
0031 uoffset_t max_depth = 64;
0032
0033 uoffset_t max_tables = 1000000;
0034
0035 bool check_alignment = true;
0036
0037 bool check_nested_flatbuffers = true;
0038
0039 size_t max_size = FLATBUFFERS_MAX_BUFFER_SIZE;
0040
0041 bool assert = false;
0042 };
0043
0044 explicit VerifierTemplate(const uint8_t *const buf, const size_t buf_len,
0045 const Options &opts)
0046 : buf_(buf), size_(buf_len), opts_(opts) {
0047 FLATBUFFERS_ASSERT(size_ < opts.max_size);
0048 }
0049
0050
0051 VerifierTemplate(const uint8_t *const buf, const size_t buf_len,
0052 const uoffset_t max_depth = 64,
0053 const uoffset_t max_tables = 1000000,
0054 const bool check_alignment = true)
0055 : VerifierTemplate(buf, buf_len, [&] {
0056 Options opts;
0057 opts.max_depth = max_depth;
0058 opts.max_tables = max_tables;
0059 opts.check_alignment = check_alignment;
0060 return opts;
0061 }()) {}
0062
0063
0064 bool Check(const bool ok) const {
0065
0066 #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE
0067 if (opts_.assert) { FLATBUFFERS_ASSERT(ok); }
0068 #endif
0069
0070 if (TrackVerifierBufferSize) {
0071 if (!ok) {
0072 upper_bound_ = 0;
0073 }
0074 }
0075 return ok;
0076 }
0077
0078
0079 bool Verify(const size_t elem, const size_t elem_len) const {
0080 if (TrackVerifierBufferSize) {
0081 auto upper_bound = elem + elem_len;
0082 if (upper_bound_ < upper_bound) {
0083 upper_bound_ = upper_bound;
0084 }
0085 }
0086 return Check(elem_len < size_ && elem <= size_ - elem_len);
0087 }
0088
0089 bool VerifyAlignment(const size_t elem, const size_t align) const {
0090 return Check((elem & (align - 1)) == 0 || !opts_.check_alignment);
0091 }
0092
0093
0094 template<typename T> bool Verify(const size_t elem) const {
0095 return VerifyAlignment(elem, sizeof(T)) && Verify(elem, sizeof(T));
0096 }
0097
0098 bool VerifyFromPointer(const uint8_t *const p, const size_t len) {
0099 return Verify(static_cast<size_t>(p - buf_), len);
0100 }
0101
0102
0103 bool VerifyFieldStruct(const uint8_t *const base, const voffset_t elem_off,
0104 const size_t elem_len, const size_t align) const {
0105 const auto f = static_cast<size_t>(base - buf_) + elem_off;
0106 return VerifyAlignment(f, align) && Verify(f, elem_len);
0107 }
0108
0109 template<typename T>
0110 bool VerifyField(const uint8_t *const base, const voffset_t elem_off,
0111 const size_t align) const {
0112 const auto f = static_cast<size_t>(base - buf_) + elem_off;
0113 return VerifyAlignment(f, align) && Verify(f, sizeof(T));
0114 }
0115
0116
0117 template<typename T> bool VerifyTable(const T *const table) {
0118 return !table || table->Verify(*this);
0119 }
0120
0121
0122 template<int &..., typename T, typename LenT>
0123 bool VerifyVector(const Vector<T, LenT> *const vec) const {
0124 return !vec || VerifyVectorOrString<LenT>(
0125 reinterpret_cast<const uint8_t *>(vec), sizeof(T));
0126 }
0127
0128
0129 template<int &..., typename T, typename LenT>
0130 bool VerifyVector(const Vector<const T *, LenT> *const vec) const {
0131 return VerifyVector(reinterpret_cast<const Vector<T, LenT> *>(vec));
0132 }
0133
0134
0135 bool VerifyString(const String *const str) const {
0136 size_t end;
0137 return !str || (VerifyVectorOrString<uoffset_t>(
0138 reinterpret_cast<const uint8_t *>(str), 1, &end) &&
0139 Verify(end, 1) &&
0140 Check(buf_[end] == '\0'));
0141 }
0142
0143
0144 template<typename LenT = uoffset_t>
0145 bool VerifyVectorOrString(const uint8_t *const vec, const size_t elem_size,
0146 size_t *const end = nullptr) const {
0147 const auto vec_offset = static_cast<size_t>(vec - buf_);
0148
0149 if (!Verify<LenT>(vec_offset)) return false;
0150
0151
0152 const LenT size = ReadScalar<LenT>(vec);
0153 const auto max_elems = opts_.max_size / elem_size;
0154 if (!Check(size < max_elems))
0155 return false;
0156 const auto byte_size = sizeof(LenT) + elem_size * size;
0157 if (end) *end = vec_offset + byte_size;
0158 return Verify(vec_offset, byte_size);
0159 }
0160
0161
0162 bool VerifyVectorOfStrings(const Vector<Offset<String>> *const vec) const {
0163 if (vec) {
0164 for (uoffset_t i = 0; i < vec->size(); i++) {
0165 if (!VerifyString(vec->Get(i))) return false;
0166 }
0167 }
0168 return true;
0169 }
0170
0171
0172 template<typename T>
0173 bool VerifyVectorOfTables(const Vector<Offset<T>> *const vec) {
0174 if (vec) {
0175 for (uoffset_t i = 0; i < vec->size(); i++) {
0176 if (!vec->Get(i)->Verify(*this)) return false;
0177 }
0178 }
0179 return true;
0180 }
0181
0182 FLATBUFFERS_SUPPRESS_UBSAN("unsigned-integer-overflow")
0183 bool VerifyTableStart(const uint8_t *const table) {
0184
0185 const auto tableo = static_cast<size_t>(table - buf_);
0186 if (!Verify<soffset_t>(tableo)) return false;
0187
0188
0189 const auto vtableo =
0190 tableo - static_cast<size_t>(ReadScalar<soffset_t>(table));
0191
0192 if (!(VerifyComplexity() && Verify<voffset_t>(vtableo) &&
0193 VerifyAlignment(ReadScalar<voffset_t>(buf_ + vtableo),
0194 sizeof(voffset_t))))
0195 return false;
0196 const auto vsize = ReadScalar<voffset_t>(buf_ + vtableo);
0197 return Check((vsize & 1) == 0) && Verify(vtableo, vsize);
0198 }
0199
0200 template<typename T>
0201 bool VerifyBufferFromStart(const char *const identifier, const size_t start) {
0202
0203
0204
0205 if (!Check(size_ >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false;
0206
0207
0208 if (identifier && !Check((size_ >= 2 * sizeof(flatbuffers::uoffset_t) &&
0209 BufferHasIdentifier(buf_ + start, identifier)))) {
0210 return false;
0211 }
0212
0213
0214 const auto o = VerifyOffset<uoffset_t>(start);
0215 if (!Check(o != 0)) return false;
0216 if (!(reinterpret_cast<const T *>(buf_ + start + o)->Verify(*this))) {
0217 return false;
0218 }
0219 if (TrackVerifierBufferSize) {
0220 if (GetComputedSize() == 0) return false;
0221 }
0222 return true;
0223 }
0224
0225 template<typename T, int &..., typename SizeT>
0226 bool VerifyNestedFlatBuffer(const Vector<uint8_t, SizeT> *const buf,
0227 const char *const identifier) {
0228
0229 if (!opts_.check_nested_flatbuffers) return true;
0230
0231
0232 if (!buf) return true;
0233
0234
0235 if (!Check(buf->size() >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false;
0236
0237 VerifierTemplate<TrackVerifierBufferSize> nested_verifier(
0238 buf->data(), buf->size(), opts_);
0239 return nested_verifier.VerifyBuffer<T>(identifier);
0240 }
0241
0242
0243 template<typename T> bool VerifyBuffer() { return VerifyBuffer<T>(nullptr); }
0244
0245 template<typename T> bool VerifyBuffer(const char *const identifier) {
0246 return VerifyBufferFromStart<T>(identifier, 0);
0247 }
0248
0249 template<typename T, typename SizeT = uoffset_t>
0250 bool VerifySizePrefixedBuffer(const char *const identifier) {
0251 return Verify<SizeT>(0U) &&
0252
0253
0254 Check(ReadScalar<SizeT>(buf_) + sizeof(SizeT) <= size_) &&
0255 VerifyBufferFromStart<T>(identifier, sizeof(SizeT));
0256 }
0257
0258 template<typename OffsetT = uoffset_t, typename SOffsetT = soffset_t>
0259 size_t VerifyOffset(const size_t start) const {
0260 if (!Verify<OffsetT>(start)) return 0;
0261 const auto o = ReadScalar<OffsetT>(buf_ + start);
0262
0263 if (!Check(o != 0)) return 0;
0264
0265 if (!Check(static_cast<SOffsetT>(o) >= 0)) return 0;
0266
0267
0268 if (!Verify(start + o, 1)) return 0;
0269 return o;
0270 }
0271
0272 template<typename OffsetT = uoffset_t>
0273 size_t VerifyOffset(const uint8_t *const base, const voffset_t start) const {
0274 return VerifyOffset<OffsetT>(static_cast<size_t>(base - buf_) + start);
0275 }
0276
0277
0278
0279
0280 bool VerifyComplexity() {
0281 depth_++;
0282 num_tables_++;
0283 return Check(depth_ <= opts_.max_depth && num_tables_ <= opts_.max_tables);
0284 }
0285
0286
0287 bool EndTable() {
0288 depth_--;
0289 return true;
0290 }
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301 size_t GetComputedSize() const {
0302 if (TrackVerifierBufferSize) {
0303 uintptr_t size = upper_bound_;
0304
0305 size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
0306 return (size > size_) ? 0 : size;
0307 }
0308
0309
0310 (void)upper_bound_;
0311 FLATBUFFERS_ASSERT(false);
0312 return 0;
0313 }
0314
0315 std::vector<uint8_t> *GetFlexReuseTracker() { return flex_reuse_tracker_; }
0316
0317 void SetFlexReuseTracker(std::vector<uint8_t> *const rt) {
0318 flex_reuse_tracker_ = rt;
0319 }
0320
0321 private:
0322 const uint8_t *buf_;
0323 const size_t size_;
0324 const Options opts_;
0325
0326 mutable size_t upper_bound_ = 0;
0327
0328 uoffset_t depth_ = 0;
0329 uoffset_t num_tables_ = 0;
0330 std::vector<uint8_t> *flex_reuse_tracker_ = nullptr;
0331 };
0332
0333
0334 template<>
0335 template<>
0336 inline size_t VerifierTemplate<false>::VerifyOffset<uoffset64_t>(
0337 const size_t start) const {
0338 return VerifyOffset<uoffset64_t, soffset64_t>(start);
0339 }
0340 template<>
0341 template<>
0342 inline size_t VerifierTemplate<true>::VerifyOffset<uoffset64_t>(
0343 const size_t start) const {
0344 return VerifyOffset<uoffset64_t, soffset64_t>(start);
0345 }
0346
0347
0348 using SizeVerifier = VerifierTemplate< true>;
0349
0350
0351
0352
0353
0354 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
0355 using Verifier = SizeVerifier;
0356 #else
0357
0358
0359 using Verifier = VerifierTemplate< false>;
0360 #endif
0361
0362 }
0363
0364 #endif