Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-08-27 09:30:29

0001 /*
0002  * Copyright 2021 Google Inc. All rights reserved.
0003  *
0004  * Licensed under the Apache License, Version 2.0 (the "License");
0005  * you may not use this file except in compliance with the License.
0006  * You may obtain a copy of the License at
0007  *
0008  *     http://www.apache.org/licenses/LICENSE-2.0
0009  *
0010  * Unless required by applicable law or agreed to in writing, software
0011  * distributed under the License is distributed on an "AS IS" BASIS,
0012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013  * See the License for the specific language governing permissions and
0014  * limitations under the License.
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 // Helper class to verify the integrity of a FlatBuffer
0026 template <bool TrackVerifierBufferSize>
0027 class VerifierTemplate FLATBUFFERS_FINAL_CLASS {
0028  public:
0029   struct Options {
0030     // The maximum nesting of tables and vectors before we call it invalid.
0031     uoffset_t max_depth = 64;
0032     // The maximum number of tables we will verify before we call it invalid.
0033     uoffset_t max_tables = 1000000;
0034     // If true, verify all data is aligned.
0035     bool check_alignment = true;
0036     // If true, run verifier on nested flatbuffers
0037     bool check_nested_flatbuffers = true;
0038     // The maximum size of a buffer.
0039     size_t max_size = FLATBUFFERS_MAX_BUFFER_SIZE;
0040     // Use assertions to check for errors.
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   // Deprecated API, please construct with VerifierTemplate::Options.
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   // Central location where any verification failures register.
0064   bool Check(const bool ok) const {
0065     // clang-format off
0066     #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE
0067       if (opts_.assert) { FLATBUFFERS_ASSERT(ok); }
0068     #endif
0069     // clang-format on
0070     if (TrackVerifierBufferSize) {
0071       if (!ok) {
0072         upper_bound_ = 0;
0073       }
0074     }
0075     return ok;
0076   }
0077 
0078   // Verify any range within the buffer.
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   // Verify a range indicated by sizeof(T).
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   // Verify relative to a known-good base pointer.
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   // Verify a pointer (may be NULL) of a table type.
0117   template<typename T> bool VerifyTable(const T *const table) {
0118     return !table || table->Verify(*this);
0119   }
0120 
0121   // Verify a pointer (may be NULL) of any vector type.
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   // Verify a pointer (may be NULL) of a vector to struct.
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   // Verify a pointer (may be NULL) to string.
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) &&           // Must have terminator
0140                     Check(buf_[end] == '\0'));  // Terminating byte must be 0.
0141   }
0142 
0143   // Common code between vectors and strings.
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     // Check we can read the size field.
0149     if (!Verify<LenT>(vec_offset)) return false;
0150     // Check the whole array. If this is a string, the byte past the array must
0151     // be 0.
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;  // Protect against byte_size overflowing.
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   // Special case for string contents, after the above has been called.
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   // Special case for table contents, after the above has been called.
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     // Check the vtable offset.
0185     const auto tableo = static_cast<size_t>(table - buf_);
0186     if (!Verify<soffset_t>(tableo)) return false;
0187     // This offset may be signed, but doing the subtraction unsigned always
0188     // gives the result we want.
0189     const auto vtableo =
0190         tableo - static_cast<size_t>(ReadScalar<soffset_t>(table));
0191     // Check the vtable size field, then check vtable fits in its entirety.
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     // Buffers have to be of some size to be valid. The reason it is a runtime
0203     // check instead of static_assert, is that nested flatbuffers go through
0204     // this call and their size is determined at runtime.
0205     if (!Check(size_ >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false;
0206 
0207     // If an identifier is provided, check that we have a buffer
0208     if (identifier && !Check((size_ >= 2 * sizeof(flatbuffers::uoffset_t) &&
0209                               BufferHasIdentifier(buf_ + start, identifier)))) {
0210       return false;
0211     }
0212 
0213     // Call T::Verify, which must be in the generated code for this type.
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     // Caller opted out of this.
0229     if (!opts_.check_nested_flatbuffers) return true;
0230 
0231     // An empty buffer is OK as it indicates not present.
0232     if (!buf) return true;
0233 
0234     // If there is a nested buffer, it must be greater than the min size.
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   // Verify this whole buffer, starting with root type T.
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            // Ensure the prefixed size is within the bounds of the provided
0253            // length.
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     // May not point to itself.
0263     if (!Check(o != 0)) return 0;
0264     // Can't wrap around larger than the max size.
0265     if (!Check(static_cast<SOffsetT>(o) >= 0)) return 0;
0266     // Must be inside the buffer to create a pointer from it (pointer outside
0267     // buffer is UB).
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   // Called at the start of a table to increase counters measuring data
0278   // structure depth and amount, and possibly bails out with false if limits set
0279   // by the constructor have been hit. Needs to be balanced with EndTable().
0280   bool VerifyComplexity() {
0281     depth_++;
0282     num_tables_++;
0283     return Check(depth_ <= opts_.max_depth && num_tables_ <= opts_.max_tables);
0284   }
0285 
0286   // Called at the end of a table to pop the depth count.
0287   bool EndTable() {
0288     depth_--;
0289     return true;
0290   }
0291 
0292   // Returns the message size in bytes.
0293   //
0294   // This should only be called after first calling VerifyBuffer or
0295   // VerifySizePrefixedBuffer.
0296   //
0297   // This method should only be called for VerifierTemplate instances
0298   // where the TrackVerifierBufferSize template parameter is true,
0299   // i.e. for SizeVerifier.  For instances where TrackVerifierBufferSize
0300   // is false, this fails at runtime or returns zero.
0301   size_t GetComputedSize() const {
0302     if (TrackVerifierBufferSize) {
0303       uintptr_t size = upper_bound_;
0304       // Align the size to uoffset_t
0305       size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
0306       return (size > size_) ?  0 : size;
0307     }
0308     // Must use SizeVerifier, or (deprecated) turn on
0309     // FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE, for this to work.
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 // Specialization for 64-bit offsets.
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 // Instance of VerifierTemplate that supports GetComputedSize().
0348 using SizeVerifier = VerifierTemplate</*TrackVerifierBufferSize = */ true>;
0349 
0350 // The FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE build configuration macro is
0351 // deprecated, and should not be defined, since it is easy to misuse in ways
0352 // that result in ODR violations. Rather than using Verifier and defining
0353 // FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE, please use SizeVerifier instead.
0354 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE  // Deprecated, see above.
0355 using Verifier = SizeVerifier;
0356 #else
0357 // Instance of VerifierTemplate that is slightly faster, but does not
0358 // support GetComputedSize().
0359 using Verifier = VerifierTemplate</*TrackVerifierBufferSize = */ false>;
0360 #endif
0361 
0362 }  // namespace flatbuffers
0363 
0364 #endif  // FLATBUFFERS_VERIFIER_H_