flatcc_verifier.h (10906B)
1 #ifndef FLATCC_VERIFIER_H 2 #define FLATCC_VERIFIER_H 3 4 #ifdef __cplusplus 5 extern "C" { 6 #endif 7 8 /* 9 * Runtime support for verifying flatbuffers. 10 * 11 * Link with the verifier implementation file. 12 * 13 * Note: 14 * 15 * 1) nested buffers will NOT have their identifier verified. 16 * The user may do so subsequently. The reason is in part because 17 * the information is not readily avaible without generated reader code, 18 * in part because the buffer might use a different, but valid, 19 * identifier and the user has no chance of specifiying this in the 20 * verifier code. The root verifier also doesn't assume a specific id 21 * but accepts a user supplied input which may be null. 22 * 23 * 2) All offsets in a buffer are verified for alignment relative to the 24 * buffer start, but the buffer itself is only assumed to aligned to 25 * uoffset_t. A reader should therefore ensure buffer alignment separately 26 * before reading the buffer. Nested buffers are in fact checked for 27 * alignment, but still only relative to the root buffer. 28 * 29 * 3) The max nesting level includes nested buffer nestings, so the 30 * verifier might fail even if the individual buffers are otherwise ok. 31 * This is to prevent abuse with lots of nested buffers. 32 * 33 * 34 * IMPORTANT: 35 * 36 * Even if verifier passes, the buffer may be invalid to access due to 37 * lack of alignemnt in memory, but the verifier is safe to call. 38 * 39 * NOTE: The buffer is not safe to modify after verification because an 40 * attacker may craft overlapping data structures such that modification 41 * of one field updates another in a way that violates the buffer 42 * constraints. This may also be caused by a clever compression scheme. 43 * 44 * It is likely faster to rewrite the table although this is also 45 * dangerous because an attacker (or even normal user) can draft a DAG 46 * that explodes when expanded carelesslessly. A safer approach is to 47 * hash all object references written and reuse those that match. This 48 * will expand references into other objects while bounding expansion 49 * and it will be safe to update assuming shared objects are ok to 50 * update. 51 * 52 */ 53 54 #include "flatcc_types.h" 55 56 #define FLATCC_VERIFY_ERROR_MAP(XX)\ 57 XX(ok, "ok")\ 58 XX(buffer_header_too_small, "buffer header too small")\ 59 XX(identifier_mismatch, "identifier mismatch")\ 60 XX(max_nesting_level_reached, "max nesting level reached")\ 61 XX(required_field_missing, "required field missing")\ 62 XX(runtime_buffer_header_not_aligned, "runtime: buffer header not aligned")\ 63 XX(runtime_buffer_size_too_large, "runtime: buffer size too large")\ 64 XX(string_not_zero_terminated, "string not zero terminated")\ 65 XX(string_out_of_range, "string out of range")\ 66 XX(struct_out_of_range, "struct out of range")\ 67 XX(struct_size_overflow, "struct size overflow")\ 68 XX(struct_unaligned, "struct unaligned")\ 69 XX(table_field_not_aligned, "table field not aligned")\ 70 XX(table_field_out_of_range, "table field out of range")\ 71 XX(table_field_size_overflow, "table field size overflow")\ 72 XX(table_header_out_of_range_or_unaligned, "table header out of range or unaligned")\ 73 XX(vector_header_out_of_range_or_unaligned, "vector header out of range or unaligned")\ 74 XX(string_header_out_of_range_or_unaligned, "string header out of range or unaligned")\ 75 XX(offset_out_of_range, "offset out of range")\ 76 XX(table_offset_out_of_range_or_unaligned, "table offset out of range or unaligned")\ 77 XX(table_size_out_of_range, "table size out of range")\ 78 XX(type_field_absent_from_required_union_field, "type field absent from required union field")\ 79 XX(type_field_absent_from_required_union_vector_field, "type field absent from required union vector field")\ 80 XX(union_cannot_have_a_table_without_a_type, "union cannot have a table without a type")\ 81 XX(union_type_NONE_cannot_have_a_value, "union value field present with type NONE")\ 82 XX(vector_count_exceeds_representable_vector_size, "vector count exceeds representable vector size")\ 83 XX(vector_out_of_range, "vector out of range")\ 84 XX(vtable_header_out_of_range, "vtable header out of range")\ 85 XX(vtable_header_too_small, "vtable header too small")\ 86 XX(vtable_offset_out_of_range_or_unaligned, "vtable offset out of range or unaligned")\ 87 XX(vtable_size_out_of_range_or_unaligned, "vtable size out of range or unaligned")\ 88 XX(vtable_size_overflow, "vtable size overflow")\ 89 XX(union_element_absent_without_type_NONE, "union element absent without type NONE")\ 90 XX(union_element_present_with_type_NONE, "union element present with type NONE")\ 91 XX(union_vector_length_mismatch, "union type and table vectors have different lengths")\ 92 XX(union_vector_verification_not_supported, "union vector verification not supported")\ 93 XX(not_supported, "not supported") 94 95 96 enum flatcc_verify_error_no { 97 #define XX(no, str) flatcc_verify_error_##no, 98 FLATCC_VERIFY_ERROR_MAP(XX) 99 #undef XX 100 }; 101 102 #define flatcc_verify_ok flatcc_verify_error_ok 103 104 const char *flatcc_verify_error_string(int err); 105 106 /* 107 * Type specific table verifier function that checks each known field 108 * for existence in the vtable and then calls the appropriate verifier 109 * function in this library. 110 * 111 * The table descriptor values have been verified for bounds, overflow, 112 * and alignment, but vtable entries after header must be verified 113 * for all fields the table verifier function understands. 114 * 115 * Calls other typespecific verifier functions recursively whenever a 116 * table field, union or table vector is encountered. 117 */ 118 typedef struct flatcc_table_verifier_descriptor flatcc_table_verifier_descriptor_t; 119 struct flatcc_table_verifier_descriptor { 120 /* Pointer to buffer. Not assumed to be aligned beyond uoffset_t. */ 121 const void *buf; 122 /* Buffer size. */ 123 flatbuffers_uoffset_t end; 124 /* Time to live: number nesting levels left before failure. */ 125 int ttl; 126 /* Vtable of current table. */ 127 const void *vtable; 128 /* Table offset relative to buffer start */ 129 flatbuffers_uoffset_t table; 130 /* Table end relative to buffer start as per vtable[1] field. */ 131 flatbuffers_voffset_t tsize; 132 /* Size of vtable in bytes. */ 133 flatbuffers_voffset_t vsize; 134 }; 135 136 typedef int flatcc_table_verifier_f(flatcc_table_verifier_descriptor_t *td); 137 138 typedef struct flatcc_union_verifier_descriptor flatcc_union_verifier_descriptor_t; 139 140 struct flatcc_union_verifier_descriptor { 141 /* Pointer to buffer. Not assumed to be aligned beyond uoffset_t. */ 142 const void *buf; 143 /* Buffer size. */ 144 flatbuffers_uoffset_t end; 145 /* Time to live: number nesting levels left before failure. */ 146 int ttl; 147 /* Type of union value to be verified */ 148 flatbuffers_utype_t type; 149 /* Offset relative to buffer start to where union value offset is stored. */ 150 flatbuffers_uoffset_t base; 151 /* Offset of union value relative to base. */ 152 flatbuffers_uoffset_t offset; 153 }; 154 155 typedef int flatcc_union_verifier_f(flatcc_union_verifier_descriptor_t *ud); 156 157 /* 158 * The `as_root` functions are normally the only functions called 159 * explicitly in this interface. 160 * 161 * If `fid` is null, the identifier is not checked and is allowed to be entirely absent. 162 * 163 * The buffer must at least be aligned to uoffset_t on systems that 164 * require aligned memory addresses. The buffer pointers alignment is 165 * not significant to internal verification of the buffer. 166 */ 167 int flatcc_verify_struct_as_root(const void *buf, size_t bufsiz, const char *fid, 168 size_t size, uint16_t align); 169 170 int flatcc_verify_struct_as_typed_root(const void *buf, size_t bufsiz, flatbuffers_thash_t thash, 171 size_t size, uint16_t align); 172 173 int flatcc_verify_table_as_root(const void *buf, size_t bufsiz, const char *fid, 174 flatcc_table_verifier_f *root_tvf); 175 176 int flatcc_verify_table_as_typed_root(const void *buf, size_t bufsiz, flatbuffers_thash_t thash, 177 flatcc_table_verifier_f *root_tvf); 178 /* 179 * The buffer header is verified by any of the `_as_root` verifiers, but 180 * this function may be used as a quick sanity check. 181 */ 182 int flatcc_verify_buffer_header(const void *buf, size_t bufsiz, const char *fid); 183 184 int flatcc_verify_typed_buffer_header(const void *buf, size_t bufsiz, flatbuffers_thash_t type_hash); 185 186 /* 187 * The following functions are typically called by a generated table 188 * verifier function. 189 */ 190 191 /* Scalar, enum or struct field. */ 192 int flatcc_verify_field(flatcc_table_verifier_descriptor_t *td, 193 flatbuffers_voffset_t id, size_t size, uint16_t align); 194 /* Vector of scalars, enums or structs. */ 195 int flatcc_verify_vector_field(flatcc_table_verifier_descriptor_t *td, 196 flatbuffers_voffset_t id, int required, size_t elem_size, uint16_t align, size_t max_count); 197 int flatcc_verify_string_field(flatcc_table_verifier_descriptor_t *td, 198 flatbuffers_voffset_t id, int required); 199 int flatcc_verify_string_vector_field(flatcc_table_verifier_descriptor_t *td, 200 flatbuffers_voffset_t id, int required); 201 int flatcc_verify_table_field(flatcc_table_verifier_descriptor_t *td, 202 flatbuffers_voffset_t id, int required, flatcc_table_verifier_f tvf); 203 int flatcc_verify_table_vector_field(flatcc_table_verifier_descriptor_t *td, 204 flatbuffers_voffset_t id, int required, flatcc_table_verifier_f tvf); 205 /* Table verifiers pass 0 as fid. */ 206 int flatcc_verify_struct_as_nested_root(flatcc_table_verifier_descriptor_t *td, 207 flatbuffers_voffset_t id, int required, const char *fid, 208 size_t size, uint16_t align); 209 int flatcc_verify_table_as_nested_root(flatcc_table_verifier_descriptor_t *td, 210 flatbuffers_voffset_t id, int required, const char *fid, 211 uint16_t align, flatcc_table_verifier_f tvf); 212 213 /* 214 * A NONE type will not accept a table being present, and a required 215 * union will not accept a type field being absent, and an absent type 216 * field will not accept a table field being present. 217 * 218 * If the above checks out and the type is not NONE, the uvf callback 219 * is executed. It must test each known table type and silently accept 220 * any unknown table type for forward compatibility. A union table 221 * value is verified without the required flag because an absent table 222 * encodes a typed NULL value while an absent type field encodes a 223 * missing union which fails if required. 224 */ 225 int flatcc_verify_union_field(flatcc_table_verifier_descriptor_t *td, 226 flatbuffers_voffset_t id, int required, flatcc_union_verifier_f uvf); 227 228 int flatcc_verify_union_vector_field(flatcc_table_verifier_descriptor_t *td, 229 flatbuffers_voffset_t id, int required, flatcc_union_verifier_f uvf); 230 231 int flatcc_verify_union_table(flatcc_union_verifier_descriptor_t *ud, flatcc_table_verifier_f *tvf); 232 int flatcc_verify_union_struct(flatcc_union_verifier_descriptor_t *ud, size_t size, uint16_t align); 233 int flatcc_verify_union_string(flatcc_union_verifier_descriptor_t *ud); 234 235 #ifdef __cplusplus 236 } 237 #endif 238 239 #endif /* FLATCC_VERIFIER_H */