• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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