LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/flatgeobuf/flatbuffers - verifier.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 70 74 94.6 %
Date: 2024-05-15 17:37:59 Functions: 32 32 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2021 Google Inc. All rights reserved.
       3             :  *
       4             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5             :  * you may not use this file except in compliance with the License.
       6             :  * You may obtain a copy of the License at
       7             :  *
       8             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9             :  *
      10             :  * Unless required by applicable law or agreed to in writing, software
      11             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             :  * See the License for the specific language governing permissions and
      14             :  * limitations under the License.
      15             :  */
      16             : 
      17             : #ifndef FLATBUFFERS_VERIFIER_H_
      18             : #define FLATBUFFERS_VERIFIER_H_
      19             : 
      20             : #include "flatbuffers/base.h"
      21             : #include "flatbuffers/vector.h"
      22             : 
      23             : namespace flatbuffers {
      24             : 
      25             : // Helper class to verify the integrity of a FlatBuffer
      26             : class Verifier FLATBUFFERS_FINAL_CLASS {
      27             :  public:
      28         841 :   Verifier(const uint8_t *buf, size_t buf_len, uoffset_t _max_depth = 64,
      29             :            uoffset_t _max_tables = 1000000, bool _check_alignment = true)
      30         841 :       : buf_(buf),
      31             :         size_(buf_len),
      32             :         depth_(0),
      33             :         max_depth_(_max_depth),
      34             :         num_tables_(0),
      35             :         max_tables_(_max_tables),
      36             :         upper_bound_(0),
      37             :         check_alignment_(_check_alignment),
      38         841 :         flex_reuse_tracker_(nullptr) {
      39         841 :     FLATBUFFERS_ASSERT(size_ < FLATBUFFERS_MAX_BUFFER_SIZE);
      40         841 :   }
      41             : 
      42             :   // Central location where any verification failures register.
      43     1616930 :   bool Check(bool ok) const {
      44             :     // clang-format off
      45             :     #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE
      46             :       FLATBUFFERS_ASSERT(ok);
      47             :     #endif
      48             :     #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
      49             :       if (!ok)
      50             :         upper_bound_ = 0;
      51             :     #endif
      52             :     // clang-format on
      53     1616930 :     return ok;
      54             :   }
      55             : 
      56             :   // Verify any range within the buffer.
      57      673670 :   bool Verify(size_t elem, size_t elem_len) const {
      58             :     // clang-format off
      59             :     #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
      60             :       auto upper_bound = elem + elem_len;
      61             :       if (upper_bound_ < upper_bound)
      62             :         upper_bound_ =  upper_bound;
      63             :     #endif
      64             :     // clang-format on
      65      673670 :     return Check(elem_len < size_ && elem <= size_ - elem_len);
      66             :   }
      67             : 
      68      470842 :   bool VerifyAlignment(size_t elem, size_t align) const {
      69      470842 :     return Check((elem & (align - 1)) == 0 || !check_alignment_);
      70             :   }
      71             : 
      72             :   // Verify a range indicated by sizeof(T).
      73      271644 :   template<typename T> bool Verify(size_t elem) const {
      74      271644 :     return VerifyAlignment(elem, sizeof(T)) && Verify(elem, sizeof(T));
      75             :   }
      76             : 
      77             :   bool VerifyFromPointer(const uint8_t *p, size_t len) {
      78             :     auto o = static_cast<size_t>(p - buf_);
      79             :     return Verify(o, len);
      80             :   }
      81             : 
      82             :   // Verify relative to a known-good base pointer.
      83             :   bool VerifyFieldStruct(const uint8_t *base, voffset_t elem_off,
      84             :                          size_t elem_len, size_t align) const {
      85             :     auto f = static_cast<size_t>(base - buf_) + elem_off;
      86             :     return VerifyAlignment(f, align) && Verify(f, elem_len);
      87             :   }
      88             : 
      89             :   template<typename T>
      90      131864 :   bool VerifyField(const uint8_t *base, voffset_t elem_off,
      91             :                    size_t align) const {
      92      131864 :     auto f = static_cast<size_t>(base - buf_) + elem_off;
      93      131864 :     return VerifyAlignment(f, align) && Verify(f, sizeof(T));
      94             :   }
      95             : 
      96             :   // Verify a pointer (may be NULL) of a table type.
      97         841 :   template<typename T> bool VerifyTable(const T *table) {
      98         841 :     return !table || table->Verify(*this);
      99             :   }
     100             : 
     101             :   // Verify a pointer (may be NULL) of any vector type.
     102        7394 :   template<typename T> bool VerifyVector(const Vector<T> *vec) const {
     103        7394 :     return !vec || VerifyVectorOrString(reinterpret_cast<const uint8_t *>(vec),
     104        7394 :                                         sizeof(T));
     105             :   }
     106             : 
     107             :   // Verify a pointer (may be NULL) of a vector to struct.
     108             :   template<typename T> bool VerifyVector(const Vector<const T *> *vec) const {
     109             :     return VerifyVector(reinterpret_cast<const Vector<T> *>(vec));
     110             :   }
     111             : 
     112             :   // Verify a pointer (may be NULL) to string.
     113      263299 :   bool VerifyString(const String *str) const {
     114             :     size_t end;
     115      329151 :     return !str || (VerifyVectorOrString(reinterpret_cast<const uint8_t *>(str),
     116       65852 :                                          1, &end) &&
     117      131704 :                     Verify(end, 1) &&           // Must have terminator
     118      329151 :                     Check(buf_[end] == '\0'));  // Terminating byte must be 0.
     119             :   }
     120             : 
     121             :   // Common code between vectors and strings.
     122       67712 :   bool VerifyVectorOrString(const uint8_t *vec, size_t elem_size,
     123             :                             size_t *end = nullptr) const {
     124       67712 :     auto veco = static_cast<size_t>(vec - buf_);
     125             :     // Check we can read the size field.
     126       67712 :     if (!Verify<uoffset_t>(veco)) return false;
     127             :     // Check the whole array. If this is a string, the byte past the array
     128             :     // must be 0.
     129       67712 :     auto size = ReadScalar<uoffset_t>(vec);
     130       67712 :     auto max_elems = FLATBUFFERS_MAX_BUFFER_SIZE / elem_size;
     131       67712 :     if (!Check(size < max_elems))
     132           0 :       return false;  // Protect against byte_size overflowing.
     133       67712 :     auto byte_size = sizeof(size) + elem_size * size;
     134       67712 :     if (end) *end = veco + byte_size;
     135       67712 :     return Verify(veco, byte_size);
     136             :   }
     137             : 
     138             :   // Special case for string contents, after the above has been called.
     139             :   bool VerifyVectorOfStrings(const Vector<Offset<String>> *vec) const {
     140             :     if (vec) {
     141             :       for (uoffset_t i = 0; i < vec->size(); i++) {
     142             :         if (!VerifyString(vec->Get(i))) return false;
     143             :       }
     144             :     }
     145             :     return true;
     146             :   }
     147             : 
     148             :   // Special case for table contents, after the above has been called.
     149        1657 :   template<typename T> bool VerifyVectorOfTables(const Vector<Offset<T>> *vec) {
     150        1657 :     if (vec) {
     151       65988 :       for (uoffset_t i = 0; i < vec->size(); i++) {
     152       65782 :         if (!vec->Get(i)->Verify(*this)) return false;
     153             :       }
     154             :     }
     155        1657 :     return true;
     156             :   }
     157             : 
     158       67334 :   __supress_ubsan__("unsigned-integer-overflow") bool VerifyTableStart(
     159             :       const uint8_t *table) {
     160             :     // Check the vtable offset.
     161       67334 :     auto tableo = static_cast<size_t>(table - buf_);
     162       67334 :     if (!Verify<soffset_t>(tableo)) return false;
     163             :     // This offset may be signed, but doing the subtraction unsigned always
     164             :     // gives the result we want.
     165       67334 :     auto vtableo = tableo - static_cast<size_t>(ReadScalar<soffset_t>(table));
     166             :     // Check the vtable size field, then check vtable fits in its entirety.
     167      134668 :     if (!( VerifyComplexity() && Verify<voffset_t>(vtableo) &&
     168       67334 :            VerifyAlignment(ReadScalar<voffset_t>(buf_ + vtableo),
     169           0 :                            sizeof(voffset_t)))) return false;
     170       67334 :     auto vsize = ReadScalar<voffset_t>(buf_ + vtableo);
     171       67334 :     return Check((vsize & 1) == 0) && Verify(vtableo, vsize);
     172             :   }
     173             : 
     174             :   template<typename T>
     175         841 :   bool VerifyBufferFromStart(const char *identifier, size_t start) {
     176         841 :     if (identifier && !Check((size_ >= 2 * sizeof(flatbuffers::uoffset_t) &&
     177           0 :                               BufferHasIdentifier(buf_ + start, identifier)))) {
     178           0 :       return false;
     179             :     }
     180             : 
     181             :     // Call T::Verify, which must be in the generated code for this type.
     182         841 :     auto o = VerifyOffset(start);
     183         841 :     return o && reinterpret_cast<const T *>(buf_ + start + o)->Verify(*this)
     184             :     // clang-format off
     185             :     #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
     186             :            && GetComputedSize()
     187             :     #endif
     188             :         ;
     189             :     // clang-format on
     190             :   }
     191             : 
     192             :   template<typename T>
     193             :   bool VerifyNestedFlatBuffer(const Vector<uint8_t> *buf,
     194             :                               const char *identifier) {
     195             :     if (!buf) return true;
     196             :     Verifier nested_verifier(buf->data(), buf->size());
     197             :     return nested_verifier.VerifyBuffer<T>(identifier);
     198             :   }
     199             : 
     200             :   // Verify this whole buffer, starting with root type T.
     201             :   template<typename T> bool VerifyBuffer() { return VerifyBuffer<T>(nullptr); }
     202             : 
     203         841 :   template<typename T> bool VerifyBuffer(const char *identifier) {
     204         841 :     return VerifyBufferFromStart<T>(identifier, 0);
     205             :   }
     206             : 
     207             :   template<typename T> bool VerifySizePrefixedBuffer(const char *identifier) {
     208             :     return Verify<uoffset_t>(0U) &&
     209             :            ReadScalar<uoffset_t>(buf_) == size_ - sizeof(uoffset_t) &&
     210             :            VerifyBufferFromStart<T>(identifier, sizeof(uoffset_t));
     211             :   }
     212             : 
     213       69264 :   uoffset_t VerifyOffset(size_t start) const {
     214       69264 :     if (!Verify<uoffset_t>(start)) return 0;
     215       69264 :     auto o = ReadScalar<uoffset_t>(buf_ + start);
     216             :     // May not point to itself.
     217       69264 :     if (!Check(o != 0)) return 0;
     218             :     // Can't wrap around / buffers are max 2GB.
     219       69264 :     if (!Check(static_cast<soffset_t>(o) >= 0)) return 0;
     220             :     // Must be inside the buffer to create a pointer from it (pointer outside
     221             :     // buffer is UB).
     222       69264 :     if (!Verify(start + o, 1)) return 0;
     223       69264 :     return o;
     224             :   }
     225             : 
     226       68423 :   uoffset_t VerifyOffset(const uint8_t *base, voffset_t start) const {
     227       68423 :     return VerifyOffset(static_cast<size_t>(base - buf_) + start);
     228             :   }
     229             : 
     230             :   // Called at the start of a table to increase counters measuring data
     231             :   // structure depth and amount, and possibly bails out with false if
     232             :   // limits set by the constructor have been hit. Needs to be balanced
     233             :   // with EndTable().
     234       67334 :   bool VerifyComplexity() {
     235       67334 :     depth_++;
     236       67334 :     num_tables_++;
     237       67334 :     return Check(depth_ <= max_depth_ && num_tables_ <= max_tables_);
     238             :   }
     239             : 
     240             :   // Called at the end of a table to pop the depth count.
     241       67334 :   bool EndTable() {
     242       67334 :     depth_--;
     243       67334 :     return true;
     244             :   }
     245             : 
     246             :   // Returns the message size in bytes
     247             :   size_t GetComputedSize() const {
     248             :     // clang-format off
     249             :     #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
     250             :       uintptr_t size = upper_bound_;
     251             :       // Align the size to uoffset_t
     252             :       size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
     253             :       return (size > size_) ?  0 : size;
     254             :     #else
     255             :       // Must turn on FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE for this to work.
     256             :       (void)upper_bound_;
     257             :       FLATBUFFERS_ASSERT(false);
     258             :       return 0;
     259             :     #endif
     260             :     // clang-format on
     261             :   }
     262             : 
     263             :   std::vector<uint8_t> *GetFlexReuseTracker() { return flex_reuse_tracker_; }
     264             : 
     265             :   void SetFlexReuseTracker(std::vector<uint8_t> *rt) {
     266             :     flex_reuse_tracker_ = rt;
     267             :   }
     268             : 
     269             :  private:
     270             :   const uint8_t *buf_;
     271             :   size_t size_;
     272             :   uoffset_t depth_;
     273             :   uoffset_t max_depth_;
     274             :   uoffset_t num_tables_;
     275             :   uoffset_t max_tables_;
     276             :   mutable size_t upper_bound_;
     277             :   bool check_alignment_;
     278             :   std::vector<uint8_t> *flex_reuse_tracker_;
     279             : };
     280             : 
     281             : }  // namespace flatbuffers
     282             : 
     283             : #endif  // FLATBUFFERS_VERIFIER_H_

Generated by: LCOV version 1.14