1 /*
2 * Copyright 2018 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 use crate::reflection_generated::reflection::{BaseType, Field, Object, Schema};
18 use crate::{FlatbufferError, FlatbufferResult};
19 use flatbuffers::{
20 ForwardsUOffset, InvalidFlatbuffer, TableVerifier, UOffsetT, Vector, Verifiable, Verifier,
21 VerifierOptions, SIZE_UOFFSET, SIZE_VOFFSET,
22 };
23 use std::collections::HashMap;
24
25 /// Verifies a buffer against its schema with custom verification options.
verify_with_options( buffer: &[u8], schema: &Schema, opts: &VerifierOptions, buf_loc_to_obj_idx: &mut HashMap<usize, i32>, ) -> FlatbufferResult<()>26 pub fn verify_with_options(
27 buffer: &[u8],
28 schema: &Schema,
29 opts: &VerifierOptions,
30 buf_loc_to_obj_idx: &mut HashMap<usize, i32>,
31 ) -> FlatbufferResult<()> {
32 let mut verifier = Verifier::new(opts, buffer);
33 if let Some(table_object) = schema.root_table() {
34 if let core::result::Result::Ok(table_pos) = verifier.get_uoffset(0) {
35 // Inserts -1 as object index for root table
36 buf_loc_to_obj_idx.insert(table_pos.try_into()?, -1);
37 let mut verified = vec![false; buffer.len()];
38 return verify_table(
39 &mut verifier,
40 &table_object,
41 table_pos.try_into()?,
42 schema,
43 &mut verified,
44 buf_loc_to_obj_idx,
45 );
46 }
47 }
48 Err(FlatbufferError::InvalidSchema)
49 }
50
verify_table( verifier: &mut Verifier, table_object: &Object, table_pos: usize, schema: &Schema, verified: &mut [bool], buf_loc_to_obj_idx: &mut HashMap<usize, i32>, ) -> FlatbufferResult<()>51 fn verify_table(
52 verifier: &mut Verifier,
53 table_object: &Object,
54 table_pos: usize,
55 schema: &Schema,
56 verified: &mut [bool],
57 buf_loc_to_obj_idx: &mut HashMap<usize, i32>,
58 ) -> FlatbufferResult<()> {
59 if table_pos < verified.len() && verified[table_pos] {
60 return Ok(());
61 }
62
63 let mut table_verifier = verifier.visit_table(table_pos)?;
64
65 for field in &table_object.fields() {
66 let field_name = field.name().to_owned();
67 table_verifier = match field.type_().base_type() {
68 BaseType::UType | BaseType::UByte => {
69 table_verifier.visit_field::<u8>(field_name, field.offset(), field.required())?
70 }
71 BaseType::Bool => {
72 table_verifier.visit_field::<bool>(field_name, field.offset(), field.required())?
73 }
74 BaseType::Byte => {
75 table_verifier.visit_field::<i8>(field_name, field.offset(), field.required())?
76 }
77 BaseType::Short => {
78 table_verifier.visit_field::<i16>(field_name, field.offset(), field.required())?
79 }
80 BaseType::UShort => {
81 table_verifier.visit_field::<u16>(field_name, field.offset(), field.required())?
82 }
83 BaseType::Int => {
84 table_verifier.visit_field::<i32>(field_name, field.offset(), field.required())?
85 }
86 BaseType::UInt => {
87 table_verifier.visit_field::<u32>(field_name, field.offset(), field.required())?
88 }
89 BaseType::Long => {
90 table_verifier.visit_field::<i64>(field_name, field.offset(), field.required())?
91 }
92 BaseType::ULong => {
93 table_verifier.visit_field::<u64>(field_name, field.offset(), field.required())?
94 }
95 BaseType::Float => {
96 table_verifier.visit_field::<f32>(field_name, field.offset(), field.required())?
97 }
98 BaseType::Double => {
99 table_verifier.visit_field::<f64>(field_name, field.offset(), field.required())?
100 }
101 BaseType::String => table_verifier.visit_field::<ForwardsUOffset<&str>>(
102 field_name,
103 field.offset(),
104 field.required(),
105 )?,
106 BaseType::Vector => {
107 verify_vector(table_verifier, &field, schema, verified, buf_loc_to_obj_idx)?
108 }
109 BaseType::Obj => {
110 if let Some(field_pos) = table_verifier.deref(field.offset())? {
111 let object_index = field.type_().index();
112 let child_obj = schema.objects().get(object_index.try_into()?);
113 if child_obj.is_struct() {
114 buf_loc_to_obj_idx.insert(field_pos, object_index);
115 verify_struct(
116 table_verifier.verifier(),
117 &child_obj,
118 field_pos,
119 schema,
120 buf_loc_to_obj_idx,
121 )?
122 } else {
123 let field_value = table_verifier.verifier().get_uoffset(field_pos)?;
124 let table_pos = field_pos.saturating_add(field_value.try_into()?);
125 buf_loc_to_obj_idx.insert(table_pos, object_index);
126 verify_table(
127 table_verifier.verifier(),
128 &child_obj,
129 table_pos,
130 schema,
131 verified,
132 buf_loc_to_obj_idx,
133 )?;
134 }
135 } else if field.required() {
136 return InvalidFlatbuffer::new_missing_required(field.name().to_string())?;
137 }
138 table_verifier
139 }
140 BaseType::Union => {
141 if let Some(field_pos) = table_verifier.deref(field.offset())? {
142 let field_value = table_verifier.verifier().get_uoffset(field_pos)?;
143 verify_union(
144 table_verifier,
145 &field,
146 field_pos.saturating_add(field_value.try_into()?),
147 schema,
148 verified,
149 buf_loc_to_obj_idx,
150 )?
151 } else if field.required() {
152 return InvalidFlatbuffer::new_missing_required(field.name().to_string())?;
153 } else {
154 table_verifier
155 }
156 }
157 _ => {
158 return Err(FlatbufferError::TypeNotSupported(
159 field
160 .type_()
161 .base_type()
162 .variant_name()
163 .unwrap_or_default()
164 .to_string(),
165 ));
166 }
167 };
168 }
169
170 table_verifier.finish();
171 verified[table_pos] = true;
172 Ok(())
173 }
174
verify_struct( verifier: &mut Verifier, struct_object: &Object, struct_pos: usize, schema: &Schema, buf_loc_to_obj_idx: &mut HashMap<usize, i32>, ) -> FlatbufferResult<()>175 fn verify_struct(
176 verifier: &mut Verifier,
177 struct_object: &Object,
178 struct_pos: usize,
179 schema: &Schema,
180 buf_loc_to_obj_idx: &mut HashMap<usize, i32>,
181 ) -> FlatbufferResult<()> {
182 verifier.range_in_buffer(struct_pos, struct_object.bytesize().try_into()?)?;
183 for field in &struct_object.fields() {
184 if field.type_().base_type() == BaseType::Obj {
185 let obj_idx = field.type_().index();
186 let child_obj = schema.objects().get(obj_idx.try_into()?);
187 if child_obj.is_struct() {
188 let field_pos = struct_pos.saturating_add(field.offset().into());
189 buf_loc_to_obj_idx.insert(field_pos, obj_idx);
190 verify_struct(verifier, &child_obj, field_pos, schema, buf_loc_to_obj_idx)?;
191 }
192 }
193 }
194 Ok(())
195 }
196
verify_vector<'a, 'b, 'c>( mut table_verifier: TableVerifier<'a, 'b, 'c>, field: &Field, schema: &Schema, verified: &mut [bool], buf_loc_to_obj_idx: &mut HashMap<usize, i32>, ) -> FlatbufferResult<TableVerifier<'a, 'b, 'c>>197 fn verify_vector<'a, 'b, 'c>(
198 mut table_verifier: TableVerifier<'a, 'b, 'c>,
199 field: &Field,
200 schema: &Schema,
201 verified: &mut [bool],
202 buf_loc_to_obj_idx: &mut HashMap<usize, i32>,
203 ) -> FlatbufferResult<TableVerifier<'a, 'b, 'c>> {
204 let field_name = field.name().to_owned();
205 match field.type_().element() {
206 BaseType::UType | BaseType::UByte => table_verifier
207 .visit_field::<ForwardsUOffset<Vector<u8>>>(
208 field_name,
209 field.offset(),
210 field.required(),
211 )
212 .map_err(FlatbufferError::VerificationError),
213 BaseType::Bool => table_verifier
214 .visit_field::<ForwardsUOffset<Vector<bool>>>(
215 field_name,
216 field.offset(),
217 field.required(),
218 )
219 .map_err(FlatbufferError::VerificationError),
220 BaseType::Byte => table_verifier
221 .visit_field::<ForwardsUOffset<Vector<i8>>>(
222 field_name,
223 field.offset(),
224 field.required(),
225 )
226 .map_err(FlatbufferError::VerificationError),
227 BaseType::Short => table_verifier
228 .visit_field::<ForwardsUOffset<Vector<i16>>>(
229 field_name,
230 field.offset(),
231 field.required(),
232 )
233 .map_err(FlatbufferError::VerificationError),
234 BaseType::UShort => table_verifier
235 .visit_field::<ForwardsUOffset<Vector<u16>>>(
236 field_name,
237 field.offset(),
238 field.required(),
239 )
240 .map_err(FlatbufferError::VerificationError),
241 BaseType::Int => table_verifier
242 .visit_field::<ForwardsUOffset<Vector<i32>>>(
243 field_name,
244 field.offset(),
245 field.required(),
246 )
247 .map_err(FlatbufferError::VerificationError),
248 BaseType::UInt => table_verifier
249 .visit_field::<ForwardsUOffset<Vector<u32>>>(
250 field_name,
251 field.offset(),
252 field.required(),
253 )
254 .map_err(FlatbufferError::VerificationError),
255 BaseType::Long => table_verifier
256 .visit_field::<ForwardsUOffset<Vector<i64>>>(
257 field_name,
258 field.offset(),
259 field.required(),
260 )
261 .map_err(FlatbufferError::VerificationError),
262 BaseType::ULong => table_verifier
263 .visit_field::<ForwardsUOffset<Vector<u64>>>(
264 field_name,
265 field.offset(),
266 field.required(),
267 )
268 .map_err(FlatbufferError::VerificationError),
269 BaseType::Float => table_verifier
270 .visit_field::<ForwardsUOffset<Vector<f32>>>(
271 field_name,
272 field.offset(),
273 field.required(),
274 )
275 .map_err(FlatbufferError::VerificationError),
276 BaseType::Double => table_verifier
277 .visit_field::<ForwardsUOffset<Vector<f64>>>(
278 field_name,
279 field.offset(),
280 field.required(),
281 )
282 .map_err(FlatbufferError::VerificationError),
283 BaseType::String => table_verifier
284 .visit_field::<ForwardsUOffset<Vector<ForwardsUOffset<&str>>>>(
285 field_name,
286 field.offset(),
287 field.required(),
288 )
289 .map_err(FlatbufferError::VerificationError),
290 BaseType::Obj => {
291 if let Some(field_pos) = table_verifier.deref(field.offset())? {
292 let verifier = table_verifier.verifier();
293 let vector_offset = verifier.get_uoffset(field_pos)?;
294 let vector_pos = field_pos.saturating_add(vector_offset.try_into()?);
295 let vector_len = verifier.get_uoffset(vector_pos)?;
296 let vector_start = vector_pos.saturating_add(SIZE_UOFFSET);
297 let child_obj_idx = field.type_().index();
298 let child_obj = schema.objects().get(child_obj_idx.try_into()?);
299 if child_obj.is_struct() {
300 let vector_size = vector_len.saturating_mul(child_obj.bytesize().try_into()?);
301 verifier.range_in_buffer(vector_start, vector_size.try_into()?)?;
302 let vector_range = core::ops::Range {
303 start: vector_start,
304 end: vector_start.saturating_add(vector_size.try_into()?),
305 };
306 for struct_pos in vector_range.step_by(child_obj.bytesize().try_into()?) {
307 buf_loc_to_obj_idx.insert(struct_pos, child_obj_idx);
308 verify_struct(
309 verifier,
310 &child_obj,
311 struct_pos,
312 schema,
313 buf_loc_to_obj_idx,
314 )?;
315 }
316 } else {
317 verifier.is_aligned::<UOffsetT>(vector_start)?;
318 let vector_size = vector_len.saturating_mul(SIZE_UOFFSET.try_into()?);
319 verifier.range_in_buffer(vector_start, vector_size.try_into()?)?;
320 let vector_range = core::ops::Range {
321 start: vector_start,
322 end: vector_start.saturating_add(vector_size.try_into()?),
323 };
324 for element_pos in vector_range.step_by(SIZE_UOFFSET) {
325 let table_pos = element_pos
326 .saturating_add(verifier.get_uoffset(element_pos)?.try_into()?);
327 buf_loc_to_obj_idx.insert(table_pos, child_obj_idx);
328 verify_table(
329 verifier,
330 &child_obj,
331 table_pos,
332 schema,
333 verified,
334 buf_loc_to_obj_idx,
335 )?;
336 }
337 }
338 } else if field.required() {
339 return InvalidFlatbuffer::new_missing_required(field.name().to_string())?;
340 }
341 Ok(table_verifier)
342 }
343 _ => {
344 return Err(FlatbufferError::TypeNotSupported(
345 field
346 .type_()
347 .base_type()
348 .variant_name()
349 .unwrap_or_default()
350 .to_string(),
351 ))
352 }
353 }
354 }
355
verify_union<'a, 'b, 'c>( mut table_verifier: TableVerifier<'a, 'b, 'c>, field: &Field, union_pos: usize, schema: &Schema, verified: &mut [bool], buf_loc_to_obj_idx: &mut HashMap<usize, i32>, ) -> FlatbufferResult<TableVerifier<'a, 'b, 'c>>356 fn verify_union<'a, 'b, 'c>(
357 mut table_verifier: TableVerifier<'a, 'b, 'c>,
358 field: &Field,
359 union_pos: usize,
360 schema: &Schema,
361 verified: &mut [bool],
362 buf_loc_to_obj_idx: &mut HashMap<usize, i32>,
363 ) -> FlatbufferResult<TableVerifier<'a, 'b, 'c>> {
364 let union_enum = schema.enums().get(field.type_().index().try_into()?);
365 if union_enum.values().is_empty() {
366 return Err(FlatbufferError::InvalidUnionEnum);
367 }
368
369 let enum_offset = field.offset() - u16::try_from(SIZE_VOFFSET)?;
370 if let Some(enum_pos) = table_verifier.deref(enum_offset)? {
371 let enum_value = table_verifier.verifier().get_u8(enum_pos)?;
372 let enum_type = union_enum
373 .values()
374 .get(enum_value.into())
375 .union_type()
376 .ok_or(FlatbufferError::InvalidUnionEnum)?;
377
378 match enum_type.base_type() {
379 BaseType::String => <&str>::run_verifier(table_verifier.verifier(), union_pos)?,
380 BaseType::Obj => {
381 let child_obj = schema.objects().get(enum_type.index().try_into()?);
382 buf_loc_to_obj_idx.insert(union_pos, enum_type.index());
383 if child_obj.is_struct() {
384 verify_struct(
385 table_verifier.verifier(),
386 &child_obj,
387 union_pos,
388 schema,
389 buf_loc_to_obj_idx,
390 )?
391 } else {
392 verify_table(
393 table_verifier.verifier(),
394 &child_obj,
395 union_pos,
396 schema,
397 verified,
398 buf_loc_to_obj_idx,
399 )?;
400 }
401 }
402 _ => {
403 return Err(FlatbufferError::TypeNotSupported(
404 enum_type
405 .base_type()
406 .variant_name()
407 .unwrap_or_default()
408 .to_string(),
409 ))
410 }
411 }
412 } else {
413 return InvalidFlatbuffer::new_inconsistent_union(
414 format!("{}_type", field.name()),
415 field.name().to_string(),
416 )?;
417 }
418
419 verified[union_pos] = true;
420 Ok(table_verifier)
421 }
422