Coverage Report

Created: 2025-06-13 06:29

/src/MapServer/src/flatgeobuf/include/flatbuffers/verifier.h
Line
Count
Source (jump to first uncovered line)
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 mapserver {
24
namespace flatbuffers {
25
26
// Helper class to verify the integrity of a FlatBuffer
27
class Verifier FLATBUFFERS_FINAL_CLASS {
28
 public:
29
  Verifier(const uint8_t *buf, size_t buf_len, uoffset_t _max_depth = 64,
30
           uoffset_t _max_tables = 1000000, bool _check_alignment = true)
31
      : buf_(buf),
32
        size_(buf_len),
33
        depth_(0),
34
        max_depth_(_max_depth),
35
        num_tables_(0),
36
        max_tables_(_max_tables),
37
        upper_bound_(0),
38
        check_alignment_(_check_alignment),
39
0
        flex_reuse_tracker_(nullptr) {
40
0
    FLATBUFFERS_ASSERT(size_ < FLATBUFFERS_MAX_BUFFER_SIZE);
41
0
  }
42
43
  // Central location where any verification failures register.
44
0
  bool Check(bool ok) const {
45
0
    // clang-format off
46
0
    #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE
47
0
      FLATBUFFERS_ASSERT(ok);
48
0
    #endif
49
0
    #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
50
0
      if (!ok)
51
0
        upper_bound_ = 0;
52
0
    #endif
53
0
    // clang-format on
54
0
    return ok;
55
0
  }
56
57
  // Verify any range within the buffer.
58
0
  bool Verify(size_t elem, size_t elem_len) const {
59
0
    // clang-format off
60
0
    #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
61
0
      auto upper_bound = elem + elem_len;
62
0
      if (upper_bound_ < upper_bound)
63
0
        upper_bound_ =  upper_bound;
64
0
    #endif
65
0
    // clang-format on
66
0
    return Check(elem_len < size_ && elem <= size_ - elem_len);
67
0
  }
68
69
0
  bool VerifyAlignment(size_t elem, size_t align) const {
70
0
    return Check((elem & (align - 1)) == 0 || !check_alignment_);
71
0
  }
72
73
  // Verify a range indicated by sizeof(T).
74
0
  template<typename T> bool Verify(size_t elem) const {
75
0
    return VerifyAlignment(elem, sizeof(T)) && Verify(elem, sizeof(T));
76
0
  }
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::Verify<unsigned int>(unsigned long) const
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::Verify<int>(unsigned long) const
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::Verify<unsigned short>(unsigned long) const
77
78
0
  bool VerifyFromPointer(const uint8_t *p, size_t len) {
79
0
    auto o = static_cast<size_t>(p - buf_);
80
0
    return Verify(o, len);
81
0
  }
82
83
  // Verify relative to a known-good base pointer.
84
  bool VerifyFieldStruct(const uint8_t *base, voffset_t elem_off,
85
0
                         size_t elem_len, size_t align) const {
86
0
    auto f = static_cast<size_t>(base - buf_) + elem_off;
87
0
    return VerifyAlignment(f, align) && Verify(f, elem_len);
88
0
  }
89
90
  template<typename T>
91
  bool VerifyField(const uint8_t *base, voffset_t elem_off,
92
0
                   size_t align) const {
93
0
    auto f = static_cast<size_t>(base - buf_) + elem_off;
94
0
    return VerifyAlignment(f, align) && Verify(f, sizeof(T));
95
0
  }
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyField<unsigned char>(unsigned char const*, unsigned short, unsigned long) const
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyField<int>(unsigned char const*, unsigned short, unsigned long) const
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyField<unsigned long>(unsigned char const*, unsigned short, unsigned long) const
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyField<unsigned short>(unsigned char const*, unsigned short, unsigned long) const
96
97
  // Verify a pointer (may be NULL) of a table type.
98
0
  template<typename T> bool VerifyTable(const T *table) {
99
0
    return !table || table->Verify(*this);
100
0
  }
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyTable<mapserver::FlatGeobuf::Crs>(mapserver::FlatGeobuf::Crs const*)
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyTable<mapserver::FlatGeobuf::Geometry>(mapserver::FlatGeobuf::Geometry const*)
101
102
  // Verify a pointer (may be NULL) of any vector type.
103
0
  template<typename T> bool VerifyVector(const Vector<T> *vec) const {
104
0
    return !vec || VerifyVectorOrString(reinterpret_cast<const uint8_t *>(vec),
105
0
                                        sizeof(T));
106
0
  }
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyVector<double>(mapserver::flatbuffers::Vector<double> const*) const
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyVector<mapserver::flatbuffers::Offset<mapserver::FlatGeobuf::Column> >(mapserver::flatbuffers::Vector<mapserver::flatbuffers::Offset<mapserver::FlatGeobuf::Column> > const*) const
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyVector<unsigned int>(mapserver::flatbuffers::Vector<unsigned int> const*) const
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyVector<unsigned long>(mapserver::flatbuffers::Vector<unsigned long> const*) const
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyVector<mapserver::flatbuffers::Offset<mapserver::FlatGeobuf::Geometry> >(mapserver::flatbuffers::Vector<mapserver::flatbuffers::Offset<mapserver::FlatGeobuf::Geometry> > const*) const
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyVector<unsigned char>(mapserver::flatbuffers::Vector<unsigned char> const*) const
107
108
  // Verify a pointer (may be NULL) of a vector to struct.
109
  template<typename T> bool VerifyVector(const Vector<const T *> *vec) const {
110
    return VerifyVector(reinterpret_cast<const Vector<T> *>(vec));
111
  }
112
113
  // Verify a pointer (may be NULL) to string.
114
0
  bool VerifyString(const String *str) const {
115
0
    size_t end;
116
0
    return !str || (VerifyVectorOrString(reinterpret_cast<const uint8_t *>(str),
117
0
                                         1, &end) &&
118
0
                    Verify(end, 1) &&           // Must have terminator
119
0
                    Check(buf_[end] == '\0'));  // Terminating byte must be 0.
120
0
  }
121
122
  // Common code between vectors and strings.
123
  bool VerifyVectorOrString(const uint8_t *vec, size_t elem_size,
124
0
                            size_t *end = nullptr) const {
125
0
    auto veco = static_cast<size_t>(vec - buf_);
126
0
    // Check we can read the size field.
127
0
    if (!Verify<uoffset_t>(veco)) return false;
128
0
    // Check the whole array. If this is a string, the byte past the array
129
0
    // must be 0.
130
0
    auto size = ReadScalar<uoffset_t>(vec);
131
0
    auto max_elems = FLATBUFFERS_MAX_BUFFER_SIZE / elem_size;
132
0
    if (!Check(size < max_elems))
133
0
      return false;  // Protect against byte_size overflowing.
134
0
    auto byte_size = sizeof(size) + elem_size * size;
135
0
    if (end) *end = veco + byte_size;
136
0
    return Verify(veco, byte_size);
137
0
  }
138
139
  // Special case for string contents, after the above has been called.
140
0
  bool VerifyVectorOfStrings(const Vector<Offset<String>> *vec) const {
141
0
    if (vec) {
142
0
      for (uoffset_t i = 0; i < vec->size(); i++) {
143
0
        if (!VerifyString(vec->Get(i))) return false;
144
0
      }
145
0
    }
146
0
    return true;
147
0
  }
148
149
  // Special case for table contents, after the above has been called.
150
0
  template<typename T> bool VerifyVectorOfTables(const Vector<Offset<T>> *vec) {
151
0
    if (vec) {
152
0
      for (uoffset_t i = 0; i < vec->size(); i++) {
153
0
        if (!vec->Get(i)->Verify(*this)) return false;
154
0
      }
155
0
    }
156
0
    return true;
157
0
  }
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyVectorOfTables<mapserver::FlatGeobuf::Column>(mapserver::flatbuffers::Vector<mapserver::flatbuffers::Offset<mapserver::FlatGeobuf::Column> > const*)
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyVectorOfTables<mapserver::FlatGeobuf::Geometry>(mapserver::flatbuffers::Vector<mapserver::flatbuffers::Offset<mapserver::FlatGeobuf::Geometry> > const*)
158
159
  __supress_ubsan__("unsigned-integer-overflow") bool VerifyTableStart(
160
0
      const uint8_t *table) {
161
0
    // Check the vtable offset.
162
0
    auto tableo = static_cast<size_t>(table - buf_);
163
0
    if (!Verify<soffset_t>(tableo)) return false;
164
0
    // This offset may be signed, but doing the subtraction unsigned always
165
0
    // gives the result we want.
166
0
    auto vtableo = tableo - static_cast<size_t>(ReadScalar<soffset_t>(table));
167
0
    // Check the vtable size field, then check vtable fits in its entirety.
168
0
    return VerifyComplexity() && Verify<voffset_t>(vtableo) &&
169
0
           VerifyAlignment(ReadScalar<voffset_t>(buf_ + vtableo),
170
0
                           sizeof(voffset_t)) &&
171
0
           Verify(vtableo, ReadScalar<voffset_t>(buf_ + vtableo));
172
0
  }
173
174
  template<typename T>
175
0
  bool VerifyBufferFromStart(const char *identifier, size_t start) {
176
0
    if (identifier && !Check((size_ >= 2 * sizeof(flatbuffers::uoffset_t) &&
177
0
                              BufferHasIdentifier(buf_ + start, identifier)))) {
178
0
      return false;
179
0
    }
180
0
181
0
    // Call T::Verify, which must be in the generated code for this type.
182
0
    auto o = VerifyOffset(start);
183
0
    return o && reinterpret_cast<const T *>(buf_ + start + o)->Verify(*this)
184
0
    // clang-format off
185
0
    #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
186
0
           && GetComputedSize()
187
0
    #endif
188
0
        ;
189
0
    // clang-format on
190
0
  }
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyBufferFromStart<mapserver::FlatGeobuf::Header>(char const*, unsigned long)
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyBufferFromStart<mapserver::FlatGeobuf::Feature>(char const*, unsigned long)
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
0
  template<typename T> bool VerifyBuffer(const char *identifier) {
204
0
    return VerifyBufferFromStart<T>(identifier, 0);
205
0
  }
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyBuffer<mapserver::FlatGeobuf::Header>(char const*)
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifyBuffer<mapserver::FlatGeobuf::Feature>(char const*)
206
207
0
  template<typename T> bool VerifySizePrefixedBuffer(const char *identifier) {
208
0
    return Verify<uoffset_t>(0U) &&
209
0
           ReadScalar<uoffset_t>(buf_) == size_ - sizeof(uoffset_t) &&
210
0
           VerifyBufferFromStart<T>(identifier, sizeof(uoffset_t));
211
0
  }
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifySizePrefixedBuffer<mapserver::FlatGeobuf::Header>(char const*)
Unexecuted instantiation: bool mapserver::flatbuffers::Verifier::VerifySizePrefixedBuffer<mapserver::FlatGeobuf::Feature>(char const*)
212
213
0
  uoffset_t VerifyOffset(size_t start) const {
214
0
    if (!Verify<uoffset_t>(start)) return 0;
215
0
    auto o = ReadScalar<uoffset_t>(buf_ + start);
216
0
    // May not point to itself.
217
0
    if (!Check(o != 0)) return 0;
218
0
    // Can't wrap around / buffers are max 2GB.
219
0
    if (!Check(static_cast<soffset_t>(o) >= 0)) return 0;
220
0
    // Must be inside the buffer to create a pointer from it (pointer outside
221
0
    // buffer is UB).
222
0
    if (!Verify(start + o, 1)) return 0;
223
0
    return o;
224
0
  }
225
226
0
  uoffset_t VerifyOffset(const uint8_t *base, voffset_t start) const {
227
0
    return VerifyOffset(static_cast<size_t>(base - buf_) + start);
228
0
  }
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
0
  bool VerifyComplexity() {
235
0
    depth_++;
236
0
    num_tables_++;
237
0
    return Check(depth_ <= max_depth_ && num_tables_ <= max_tables_);
238
0
  }
239
240
  // Called at the end of a table to pop the depth count.
241
0
  bool EndTable() {
242
0
    depth_--;
243
0
    return true;
244
0
  }
245
246
  // Returns the message size in bytes
247
0
  size_t GetComputedSize() const {
248
0
    // clang-format off
249
0
    #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
250
0
      uintptr_t size = upper_bound_;
251
0
      // Align the size to uoffset_t
252
0
      size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
253
0
      return (size > size_) ?  0 : size;
254
0
    #else
255
0
      // Must turn on FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE for this to work.
256
0
      (void)upper_bound_;
257
0
      FLATBUFFERS_ASSERT(false);
258
0
      return 0;
259
0
    #endif
260
0
    // clang-format on
261
0
  }
262
263
0
  std::vector<uint8_t> *GetFlexReuseTracker() { return flex_reuse_tracker_; }
264
265
0
  void SetFlexReuseTracker(std::vector<uint8_t> *rt) {
266
0
    flex_reuse_tracker_ = rt;
267
0
  }
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
}  // namespace mapserver
283
284
#endif  // FLATBUFFERS_VERIFIER_H_