verifier.h 9.4 KB

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