1 /* Copyright 2018 Mozilla Foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 use std::collections::HashSet;
17 use std::result;
18 use std::str;
19
20 use crate::limits::{
21 MAX_WASM_FUNCTIONS, MAX_WASM_FUNCTION_LOCALS, MAX_WASM_GLOBALS, MAX_WASM_MEMORIES,
22 MAX_WASM_MEMORY_PAGES, MAX_WASM_TABLES, MAX_WASM_TYPES,
23 };
24
25 use crate::binary_reader::BinaryReader;
26
27 use crate::primitives::{
28 BinaryReaderError, ExternalKind, FuncType, GlobalType, ImportSectionEntryType, MemoryType,
29 Operator, ResizableLimits, Result, SectionCode, TableType, Type,
30 };
31
32 use crate::operators_validator::{
33 is_subtype_supertype, FunctionEnd, OperatorValidator, OperatorValidatorConfig,
34 DEFAULT_OPERATOR_VALIDATOR_CONFIG,
35 };
36 use crate::parser::{Parser, ParserInput, ParserState, WasmDecoder};
37 use crate::{ElemSectionEntryTable, ElementItem};
38 use crate::{WasmFuncType, WasmGlobalType, WasmMemoryType, WasmModuleResources, WasmTableType};
39
40 use crate::readers::FunctionBody;
41
42 type ValidatorResult<'a, T> = result::Result<T, ParserState<'a>>;
43
44 struct InitExpressionState {
45 ty: Type,
46 global_count: usize,
47 function_count: usize,
48 validated: bool,
49 }
50
51 #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
52 enum SectionOrderState {
53 Initial,
54 Type,
55 Import,
56 Function,
57 Table,
58 Memory,
59 Global,
60 Export,
61 Start,
62 Element,
63 DataCount,
64 Code,
65 Data,
66 }
67
68 impl SectionOrderState {
from_section_code(code: &SectionCode) -> Option<SectionOrderState>69 pub fn from_section_code(code: &SectionCode) -> Option<SectionOrderState> {
70 match *code {
71 SectionCode::Type => Some(SectionOrderState::Type),
72 SectionCode::Import => Some(SectionOrderState::Import),
73 SectionCode::Function => Some(SectionOrderState::Function),
74 SectionCode::Table => Some(SectionOrderState::Table),
75 SectionCode::Memory => Some(SectionOrderState::Memory),
76 SectionCode::Global => Some(SectionOrderState::Global),
77 SectionCode::Export => Some(SectionOrderState::Export),
78 SectionCode::Start => Some(SectionOrderState::Start),
79 SectionCode::Element => Some(SectionOrderState::Element),
80 SectionCode::Code => Some(SectionOrderState::Code),
81 SectionCode::Data => Some(SectionOrderState::Data),
82 SectionCode::DataCount => Some(SectionOrderState::DataCount),
83 _ => None,
84 }
85 }
86 }
87
88 #[derive(Copy, Clone)]
89 pub struct ValidatingParserConfig {
90 pub operator_config: OperatorValidatorConfig,
91 }
92
93 const DEFAULT_VALIDATING_PARSER_CONFIG: ValidatingParserConfig = ValidatingParserConfig {
94 operator_config: DEFAULT_OPERATOR_VALIDATOR_CONFIG,
95 };
96
97 struct ValidatingParserResources {
98 types: Vec<FuncType>,
99 tables: Vec<TableType>,
100 memories: Vec<MemoryType>,
101 globals: Vec<GlobalType>,
102 element_count: u32,
103 data_count: Option<u32>,
104 func_type_indices: Vec<u32>,
105 }
106
107 impl<'a> WasmModuleResources for ValidatingParserResources {
108 type FuncType = crate::FuncType;
109 type TableType = crate::TableType;
110 type MemoryType = crate::MemoryType;
111 type GlobalType = crate::GlobalType;
112
type_at(&self, at: u32) -> Option<&Self::FuncType>113 fn type_at(&self, at: u32) -> Option<&Self::FuncType> {
114 self.types.get(at as usize)
115 }
116
table_at(&self, at: u32) -> Option<&Self::TableType>117 fn table_at(&self, at: u32) -> Option<&Self::TableType> {
118 self.tables.get(at as usize)
119 }
120
memory_at(&self, at: u32) -> Option<&Self::MemoryType>121 fn memory_at(&self, at: u32) -> Option<&Self::MemoryType> {
122 self.memories.get(at as usize)
123 }
124
global_at(&self, at: u32) -> Option<&Self::GlobalType>125 fn global_at(&self, at: u32) -> Option<&Self::GlobalType> {
126 self.globals.get(at as usize)
127 }
128
func_type_id_at(&self, at: u32) -> Option<u32>129 fn func_type_id_at(&self, at: u32) -> Option<u32> {
130 self.func_type_indices.get(at as usize).copied()
131 }
132
element_count(&self) -> u32133 fn element_count(&self) -> u32 {
134 self.element_count
135 }
136
data_count(&self) -> u32137 fn data_count(&self) -> u32 {
138 self.data_count.unwrap_or(0)
139 }
140 }
141
142 pub struct ValidatingParser<'a> {
143 parser: Parser<'a>,
144 validation_error: Option<ParserState<'a>>,
145 read_position: Option<usize>,
146 section_order_state: SectionOrderState,
147 resources: ValidatingParserResources,
148 current_func_index: u32,
149 func_imports_count: u32,
150 init_expression_state: Option<InitExpressionState>,
151 data_found: u32,
152 exported_names: HashSet<String>,
153 current_operator_validator: Option<OperatorValidator>,
154 config: ValidatingParserConfig,
155 }
156
157 impl<'a> ValidatingParser<'a> {
new(bytes: &[u8], config: Option<ValidatingParserConfig>) -> ValidatingParser158 pub fn new(bytes: &[u8], config: Option<ValidatingParserConfig>) -> ValidatingParser {
159 ValidatingParser {
160 parser: Parser::new(bytes),
161 validation_error: None,
162 read_position: None,
163 section_order_state: SectionOrderState::Initial,
164 resources: ValidatingParserResources {
165 types: Vec::new(),
166 tables: Vec::new(),
167 memories: Vec::new(),
168 globals: Vec::new(),
169 element_count: 0,
170 data_count: None,
171 func_type_indices: Vec::new(),
172 },
173 current_func_index: 0,
174 func_imports_count: 0,
175 current_operator_validator: None,
176 init_expression_state: None,
177 data_found: 0,
178 exported_names: HashSet::new(),
179 config: config.unwrap_or(DEFAULT_VALIDATING_PARSER_CONFIG),
180 }
181 }
182
get_resources( &self, ) -> &dyn WasmModuleResources< FuncType = crate::FuncType, TableType = crate::TableType, MemoryType = crate::MemoryType, GlobalType = crate::GlobalType, >183 pub fn get_resources(
184 &self,
185 ) -> &dyn WasmModuleResources<
186 FuncType = crate::FuncType,
187 TableType = crate::TableType,
188 MemoryType = crate::MemoryType,
189 GlobalType = crate::GlobalType,
190 > {
191 &self.resources
192 }
193
set_validation_error(&mut self, message: &'static str)194 fn set_validation_error(&mut self, message: &'static str) {
195 self.validation_error = Some(ParserState::Error(BinaryReaderError {
196 message,
197 offset: self.read_position.unwrap(),
198 }))
199 }
200
create_error<T>(&self, message: &'static str) -> ValidatorResult<'a, T>201 fn create_error<T>(&self, message: &'static str) -> ValidatorResult<'a, T> {
202 Err(ParserState::Error(BinaryReaderError {
203 message,
204 offset: self.read_position.unwrap(),
205 }))
206 }
207
check_value_type(&self, ty: Type) -> ValidatorResult<'a, ()>208 fn check_value_type(&self, ty: Type) -> ValidatorResult<'a, ()> {
209 match ty {
210 Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()),
211 Type::NullRef | Type::AnyFunc | Type::AnyRef => {
212 if !self.config.operator_config.enable_reference_types {
213 return self.create_error("reference types support is not enabled");
214 }
215 Ok(())
216 }
217 Type::V128 => {
218 if !self.config.operator_config.enable_simd {
219 return self.create_error("SIMD support is not enabled");
220 }
221 Ok(())
222 }
223 _ => self.create_error("invalid value type"),
224 }
225 }
226
check_value_types(&self, types: &[Type]) -> ValidatorResult<'a, ()>227 fn check_value_types(&self, types: &[Type]) -> ValidatorResult<'a, ()> {
228 for ty in types {
229 self.check_value_type(*ty)?;
230 }
231 Ok(())
232 }
233
check_limits(&self, limits: &ResizableLimits) -> ValidatorResult<'a, ()>234 fn check_limits(&self, limits: &ResizableLimits) -> ValidatorResult<'a, ()> {
235 if limits.maximum.is_some() && limits.initial > limits.maximum.unwrap() {
236 return self.create_error("maximum limits less than initial");
237 }
238 Ok(())
239 }
240
check_func_type(&self, func_type: &FuncType) -> ValidatorResult<'a, ()>241 fn check_func_type(&self, func_type: &FuncType) -> ValidatorResult<'a, ()> {
242 if let Type::Func = func_type.form {
243 self.check_value_types(&*func_type.params)?;
244 self.check_value_types(&*func_type.returns)?;
245 if !self.config.operator_config.enable_multi_value && func_type.returns.len() > 1 {
246 self.create_error("func type returns multiple values")
247 } else {
248 Ok(())
249 }
250 } else {
251 self.create_error("type signature is not a func")
252 }
253 }
254
check_table_type(&self, table_type: &TableType) -> ValidatorResult<'a, ()>255 fn check_table_type(&self, table_type: &TableType) -> ValidatorResult<'a, ()> {
256 match table_type.element_type {
257 Type::AnyFunc => {}
258 _ => {
259 if !self.config.operator_config.enable_reference_types {
260 return self.create_error("element is not anyfunc");
261 }
262 }
263 }
264 self.check_limits(&table_type.limits)
265 }
266
check_memory_type(&self, memory_type: &MemoryType) -> ValidatorResult<'a, ()>267 fn check_memory_type(&self, memory_type: &MemoryType) -> ValidatorResult<'a, ()> {
268 self.check_limits(&memory_type.limits)?;
269 let initial = memory_type.limits.initial;
270 if initial as usize > MAX_WASM_MEMORY_PAGES {
271 return self.create_error("memory initial value exceeds limit");
272 }
273 let maximum = memory_type.limits.maximum;
274 if maximum.is_some() && maximum.unwrap() as usize > MAX_WASM_MEMORY_PAGES {
275 return self.create_error("memory maximum value exceeds limit");
276 }
277 Ok(())
278 }
279
check_global_type(&self, global_type: GlobalType) -> ValidatorResult<'a, ()>280 fn check_global_type(&self, global_type: GlobalType) -> ValidatorResult<'a, ()> {
281 self.check_value_type(global_type.content_type)
282 }
283
check_import_entry(&self, import_type: &ImportSectionEntryType) -> ValidatorResult<'a, ()>284 fn check_import_entry(&self, import_type: &ImportSectionEntryType) -> ValidatorResult<'a, ()> {
285 match *import_type {
286 ImportSectionEntryType::Function(type_index) => {
287 if self.resources.func_type_indices.len() >= MAX_WASM_FUNCTIONS {
288 return self.create_error("functions count out of bounds");
289 }
290 if type_index as usize >= self.resources.types.len() {
291 return self.create_error("type index out of bounds");
292 }
293 Ok(())
294 }
295 ImportSectionEntryType::Table(ref table_type) => {
296 if !self.config.operator_config.enable_reference_types
297 && self.resources.tables.len() >= MAX_WASM_TABLES
298 {
299 return self.create_error("tables count must be at most 1");
300 }
301 self.check_table_type(table_type)
302 }
303 ImportSectionEntryType::Memory(ref memory_type) => {
304 if self.resources.memories.len() >= MAX_WASM_MEMORIES {
305 return self.create_error("memory count must be at most 1");
306 }
307 self.check_memory_type(memory_type)
308 }
309 ImportSectionEntryType::Global(global_type) => {
310 if self.resources.globals.len() >= MAX_WASM_GLOBALS {
311 return self.create_error("functions count out of bounds");
312 }
313 self.check_global_type(global_type)
314 }
315 }
316 }
317
check_init_expression_operator(&self, operator: &Operator) -> ValidatorResult<'a, ()>318 fn check_init_expression_operator(&self, operator: &Operator) -> ValidatorResult<'a, ()> {
319 let state = self.init_expression_state.as_ref().unwrap();
320 if state.validated {
321 return self.create_error("only one init_expr operator is expected");
322 }
323 let ty = match *operator {
324 Operator::I32Const { .. } => Type::I32,
325 Operator::I64Const { .. } => Type::I64,
326 Operator::F32Const { .. } => Type::F32,
327 Operator::F64Const { .. } => Type::F64,
328 Operator::RefNull => {
329 if !self.config.operator_config.enable_reference_types {
330 return self.create_error("reference types support is not enabled");
331 }
332 Type::NullRef
333 }
334 Operator::V128Const { .. } => {
335 if !self.config.operator_config.enable_simd {
336 return self.create_error("SIMD support is not enabled");
337 }
338 Type::V128
339 }
340 Operator::GlobalGet { global_index } => {
341 if global_index as usize >= state.global_count {
342 return self.create_error("init_expr global index out of bounds");
343 }
344 self.resources.globals[global_index as usize].content_type
345 }
346 Operator::RefFunc { function_index } => {
347 if function_index as usize >= state.function_count {
348 return self.create_error("init_expr function index out of bounds");
349 }
350 Type::AnyFunc
351 }
352 _ => return self.create_error("invalid init_expr operator"),
353 };
354 if !is_subtype_supertype(ty, state.ty) {
355 return self.create_error("invalid init_expr type");
356 }
357 Ok(())
358 }
359
check_export_entry( &self, field: &str, kind: ExternalKind, index: u32, ) -> ValidatorResult<'a, ()>360 fn check_export_entry(
361 &self,
362 field: &str,
363 kind: ExternalKind,
364 index: u32,
365 ) -> ValidatorResult<'a, ()> {
366 if self.exported_names.contains(field) {
367 return self.create_error("non-unique export name");
368 }
369 match kind {
370 ExternalKind::Function => {
371 if index as usize >= self.resources.func_type_indices.len() {
372 return self.create_error("exported function index out of bounds");
373 }
374 }
375 ExternalKind::Table => {
376 if index as usize >= self.resources.tables.len() {
377 return self.create_error("exported table index out of bounds");
378 }
379 }
380 ExternalKind::Memory => {
381 if index as usize >= self.resources.memories.len() {
382 return self.create_error("exported memory index out of bounds");
383 }
384 }
385 ExternalKind::Global => {
386 if index as usize >= self.resources.globals.len() {
387 return self.create_error("exported global index out of bounds");
388 }
389 }
390 };
391 Ok(())
392 }
393
check_start(&self, func_index: u32) -> ValidatorResult<'a, ()>394 fn check_start(&self, func_index: u32) -> ValidatorResult<'a, ()> {
395 if func_index as usize >= self.resources.func_type_indices.len() {
396 return self.create_error("start function index out of bounds");
397 }
398 let type_index = self.resources.func_type_indices[func_index as usize];
399 let ty = &self.resources.types[type_index as usize];
400 if !ty.params.is_empty() || !ty.returns.is_empty() {
401 return self.create_error("invlid start function type");
402 }
403 Ok(())
404 }
405
process_begin_section(&self, code: &SectionCode) -> ValidatorResult<'a, SectionOrderState>406 fn process_begin_section(&self, code: &SectionCode) -> ValidatorResult<'a, SectionOrderState> {
407 let order_state = SectionOrderState::from_section_code(code);
408 Ok(match self.section_order_state {
409 SectionOrderState::Initial => match order_state {
410 Some(section) => section,
411 _ => SectionOrderState::Initial,
412 },
413 previous => {
414 if let Some(order_state_unwraped) = order_state {
415 if previous >= order_state_unwraped {
416 return self.create_error("section out of order");
417 }
418 order_state_unwraped
419 } else {
420 previous
421 }
422 }
423 })
424 }
425
process_state(&mut self)426 fn process_state(&mut self) {
427 match *self.parser.last_state() {
428 ParserState::BeginWasm { version } => {
429 if version != 1 {
430 self.set_validation_error("bad wasm file version");
431 }
432 }
433 ParserState::BeginSection { ref code, .. } => {
434 let check = self.process_begin_section(code);
435 if check.is_err() {
436 self.validation_error = check.err();
437 } else {
438 self.section_order_state = check.ok().unwrap();
439 }
440 }
441 ParserState::TypeSectionEntry(ref func_type) => {
442 let check = self.check_func_type(func_type);
443 if check.is_err() {
444 self.validation_error = check.err();
445 } else if self.resources.types.len() > MAX_WASM_TYPES {
446 self.set_validation_error("types count is out of bounds");
447 } else {
448 self.resources.types.push(func_type.clone());
449 }
450 }
451 ParserState::ImportSectionEntry { ref ty, .. } => {
452 let check = self.check_import_entry(ty);
453 if check.is_err() {
454 self.validation_error = check.err();
455 } else {
456 match *ty {
457 ImportSectionEntryType::Function(type_index) => {
458 self.func_imports_count += 1;
459 self.resources.func_type_indices.push(type_index);
460 }
461 ImportSectionEntryType::Table(ref table_type) => {
462 self.resources.tables.push(table_type.clone());
463 }
464 ImportSectionEntryType::Memory(ref memory_type) => {
465 self.resources.memories.push(memory_type.clone());
466 }
467 ImportSectionEntryType::Global(ref global_type) => {
468 self.resources.globals.push(global_type.clone());
469 }
470 }
471 }
472 }
473 ParserState::FunctionSectionEntry(type_index) => {
474 if type_index as usize >= self.resources.types.len() {
475 self.set_validation_error("func type index out of bounds");
476 } else if self.resources.func_type_indices.len() >= MAX_WASM_FUNCTIONS {
477 self.set_validation_error("functions count out of bounds");
478 } else {
479 self.resources.func_type_indices.push(type_index);
480 }
481 }
482 ParserState::TableSectionEntry(ref table_type) => {
483 if !self.config.operator_config.enable_reference_types
484 && self.resources.tables.len() >= MAX_WASM_TABLES
485 {
486 self.set_validation_error("tables count must be at most 1");
487 } else {
488 self.validation_error = self.check_table_type(table_type).err();
489 self.resources.tables.push(table_type.clone());
490 }
491 }
492 ParserState::MemorySectionEntry(ref memory_type) => {
493 if self.resources.memories.len() >= MAX_WASM_MEMORIES {
494 self.set_validation_error("memories count must be at most 1");
495 } else {
496 self.validation_error = self.check_memory_type(memory_type).err();
497 self.resources.memories.push(memory_type.clone());
498 }
499 }
500 ParserState::BeginGlobalSectionEntry(global_type) => {
501 if self.resources.globals.len() >= MAX_WASM_GLOBALS {
502 self.set_validation_error("globals count out of bounds");
503 } else {
504 self.validation_error = self.check_global_type(global_type).err();
505 self.init_expression_state = Some(InitExpressionState {
506 ty: global_type.content_type,
507 global_count: self.resources.globals.len(),
508 function_count: self.resources.func_type_indices.len(),
509 validated: false,
510 });
511 self.resources.globals.push(global_type);
512 }
513 }
514 ParserState::BeginInitExpressionBody => {
515 assert!(self.init_expression_state.is_some());
516 }
517 ParserState::InitExpressionOperator(ref operator) => {
518 self.validation_error = self.check_init_expression_operator(operator).err();
519 self.init_expression_state.as_mut().unwrap().validated = true;
520 }
521 ParserState::EndInitExpressionBody => {
522 if !self.init_expression_state.as_ref().unwrap().validated {
523 self.set_validation_error("init_expr is empty");
524 }
525 self.init_expression_state = None;
526 }
527 ParserState::ExportSectionEntry { field, kind, index } => {
528 self.validation_error = self.check_export_entry(field, kind, index).err();
529 self.exported_names.insert(String::from(field));
530 }
531 ParserState::StartSectionEntry(func_index) => {
532 self.validation_error = self.check_start(func_index).err();
533 }
534 ParserState::DataCountSectionEntry(count) => {
535 self.resources.data_count = Some(count);
536 }
537 ParserState::BeginElementSectionEntry { table, ty } => {
538 self.resources.element_count += 1;
539 if let ElemSectionEntryTable::Active(table_index) = table {
540 let table = match self.resources.tables.get(table_index as usize) {
541 Some(t) => t,
542 None => {
543 self.set_validation_error("element section table index out of bounds");
544 return;
545 }
546 };
547 if !is_subtype_supertype(ty, table.element_type) {
548 self.set_validation_error("element_type != table type");
549 return;
550 }
551 if !self.config.operator_config.enable_reference_types && ty != Type::AnyFunc {
552 self.set_validation_error("element_type != anyfunc is not supported yet");
553 return;
554 }
555 self.init_expression_state = Some(InitExpressionState {
556 ty: Type::I32,
557 global_count: self.resources.globals.len(),
558 function_count: self.resources.func_type_indices.len(),
559 validated: false,
560 });
561 }
562 }
563 ParserState::ElementSectionEntryBody(ref indices) => {
564 for item in &**indices {
565 if let ElementItem::Func(func_index) = item {
566 if *func_index as usize >= self.resources.func_type_indices.len() {
567 self.set_validation_error("element func index out of bounds");
568 break;
569 }
570 }
571 }
572 }
573 ParserState::BeginFunctionBody { .. } => {
574 let index = (self.current_func_index + self.func_imports_count) as usize;
575 if index as usize >= self.resources.func_type_indices.len() {
576 self.set_validation_error("func type is not defined");
577 }
578 }
579 ParserState::FunctionBodyLocals { ref locals } => {
580 let index = (self.current_func_index + self.func_imports_count) as usize;
581 let func_type =
582 &self.resources.types[self.resources.func_type_indices[index] as usize];
583 let operator_config = self.config.operator_config;
584 self.current_operator_validator =
585 Some(OperatorValidator::new(func_type, locals, operator_config));
586 }
587 ParserState::CodeOperator(ref operator) => {
588 let check = self
589 .current_operator_validator
590 .as_mut()
591 .unwrap()
592 .process_operator(operator, &self.resources);
593
594 if let Err(err) = check {
595 self.set_validation_error(err);
596 }
597 }
598 ParserState::EndFunctionBody => {
599 let check = self
600 .current_operator_validator
601 .as_ref()
602 .unwrap()
603 .process_end_function();
604 if let Err(err) = check {
605 self.set_validation_error(err);
606 }
607 self.current_func_index += 1;
608 self.current_operator_validator = None;
609 }
610 ParserState::BeginDataSectionEntryBody(_) => {
611 self.data_found += 1;
612 }
613 ParserState::BeginActiveDataSectionEntry(memory_index) => {
614 if memory_index as usize >= self.resources.memories.len() {
615 self.set_validation_error("data section memory index out of bounds");
616 } else {
617 self.init_expression_state = Some(InitExpressionState {
618 ty: Type::I32,
619 global_count: self.resources.globals.len(),
620 function_count: self.resources.func_type_indices.len(),
621 validated: false,
622 });
623 }
624 }
625 ParserState::EndWasm => {
626 if self.resources.func_type_indices.len()
627 != self.current_func_index as usize + self.func_imports_count as usize
628 {
629 self.set_validation_error(
630 "function and code section have inconsistent lengths",
631 );
632 }
633 if let Some(data_count) = self.resources.data_count {
634 if data_count != self.data_found {
635 self.set_validation_error("data count section and passive data mismatch");
636 }
637 }
638 }
639 _ => (),
640 };
641 }
642
create_validating_operator_parser<'b>(&mut self) -> ValidatingOperatorParser<'b> where 'a: 'b,643 pub fn create_validating_operator_parser<'b>(&mut self) -> ValidatingOperatorParser<'b>
644 where
645 'a: 'b,
646 {
647 let func_body_offset = match *self.last_state() {
648 ParserState::BeginFunctionBody { .. } => self.parser.current_position(),
649 _ => panic!("Invalid reader state"),
650 };
651 self.read();
652 let operator_validator = match *self.last_state() {
653 ParserState::FunctionBodyLocals { ref locals } => {
654 let index = (self.current_func_index + self.func_imports_count) as usize;
655 let func_type =
656 &self.resources.types[self.resources.func_type_indices[index] as usize];
657 let operator_config = self.config.operator_config;
658 OperatorValidator::new(func_type, locals, operator_config)
659 }
660 _ => panic!("Invalid reader state"),
661 };
662 let reader = self.create_binary_reader();
663 ValidatingOperatorParser::new(operator_validator, reader, func_body_offset)
664 }
665 }
666
667 impl<'a> WasmDecoder<'a> for ValidatingParser<'a> {
read(&mut self) -> &ParserState<'a>668 fn read(&mut self) -> &ParserState<'a> {
669 if self.validation_error.is_some() {
670 panic!("Parser in error state: validation");
671 }
672 self.read_position = Some(self.parser.current_position());
673 self.parser.read();
674 self.process_state();
675 self.last_state()
676 }
677
push_input(&mut self, input: ParserInput)678 fn push_input(&mut self, input: ParserInput) {
679 match input {
680 ParserInput::SkipSection => panic!("Not supported"),
681 ParserInput::ReadSectionRawData => panic!("Not supported"),
682 ParserInput::SkipFunctionBody => {
683 self.current_func_index += 1;
684 self.parser.push_input(input);
685 }
686 _ => self.parser.push_input(input),
687 }
688 }
689
read_with_input(&mut self, input: ParserInput) -> &ParserState<'a>690 fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a> {
691 self.push_input(input);
692 self.read()
693 }
694
create_binary_reader<'b>(&mut self) -> BinaryReader<'b> where 'a: 'b,695 fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b>
696 where
697 'a: 'b,
698 {
699 if let ParserState::BeginSection { .. } = *self.parser.last_state() {
700 panic!("Not supported");
701 }
702 self.parser.create_binary_reader()
703 }
704
last_state(&self) -> &ParserState<'a>705 fn last_state(&self) -> &ParserState<'a> {
706 if self.validation_error.is_some() {
707 self.validation_error.as_ref().unwrap()
708 } else {
709 self.parser.last_state()
710 }
711 }
712 }
713
714 pub struct ValidatingOperatorParser<'b> {
715 operator_validator: OperatorValidator,
716 reader: BinaryReader<'b>,
717 func_body_offset: usize,
718 end_function: bool,
719 }
720
721 impl<'b> ValidatingOperatorParser<'b> {
new<'c>( operator_validator: OperatorValidator, reader: BinaryReader<'c>, func_body_offset: usize, ) -> ValidatingOperatorParser<'c> where 'b: 'c,722 pub(crate) fn new<'c>(
723 operator_validator: OperatorValidator,
724 reader: BinaryReader<'c>,
725 func_body_offset: usize,
726 ) -> ValidatingOperatorParser<'c>
727 where
728 'b: 'c,
729 {
730 ValidatingOperatorParser {
731 operator_validator,
732 reader,
733 func_body_offset,
734 end_function: false,
735 }
736 }
737
eof(&self) -> bool738 pub fn eof(&self) -> bool {
739 self.end_function
740 }
741
current_position(&self) -> usize742 pub fn current_position(&self) -> usize {
743 self.reader.current_position()
744 }
745
is_dead_code(&self) -> bool746 pub fn is_dead_code(&self) -> bool {
747 self.operator_validator.is_dead_code()
748 }
749
750 /// Creates a BinaryReader when current state is ParserState::BeginSection
751 /// or ParserState::BeginFunctionBody.
752 ///
753 /// # Examples
754 /// ```
755 /// # let data = &[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x84,
756 /// # 0x80, 0x80, 0x80, 0x0, 0x1, 0x60, 0x0, 0x0, 0x3, 0x83,
757 /// # 0x80, 0x80, 0x80, 0x0, 0x2, 0x0, 0x0, 0x6, 0x81, 0x80,
758 /// # 0x80, 0x80, 0x0, 0x0, 0xa, 0x91, 0x80, 0x80, 0x80, 0x0,
759 /// # 0x2, 0x83, 0x80, 0x80, 0x80, 0x0, 0x0, 0x1, 0xb, 0x83,
760 /// # 0x80, 0x80, 0x80, 0x0, 0x0, 0x0, 0xb];
761 /// use wasmparser::{WasmDecoder, ParserState, ValidatingParser};
762 /// let mut parser = ValidatingParser::new(data, None);
763 /// let mut i = 0;
764 /// loop {
765 /// {
766 /// match *parser.read() {
767 /// ParserState::Error(_) |
768 /// ParserState::EndWasm => break,
769 /// ParserState::BeginFunctionBody {..} => (),
770 /// _ => continue
771 /// }
772 /// }
773 /// let mut reader = parser.create_validating_operator_parser();
774 /// println!("Function {}", i);
775 /// i += 1;
776 /// while !reader.eof() {
777 /// let read = reader.next(parser.get_resources());
778 /// if let Ok(ref op) = read {
779 /// println!(" {:?}", op);
780 /// } else {
781 /// panic!(" Bad wasm code {:?}", read.err());
782 /// }
783 /// }
784 /// }
785 /// ```
next<'c, F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>( &mut self, resources: &dyn WasmModuleResources< FuncType = F, TableType = T, MemoryType = M, GlobalType = G, >, ) -> Result<Operator<'c>> where 'b: 'c,786 pub fn next<'c, F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>(
787 &mut self,
788 resources: &dyn WasmModuleResources<
789 FuncType = F,
790 TableType = T,
791 MemoryType = M,
792 GlobalType = G,
793 >,
794 ) -> Result<Operator<'c>>
795 where
796 'b: 'c,
797 {
798 let op = self.reader.read_operator()?;
799 match self.operator_validator.process_operator(&op, resources) {
800 Err(err) => {
801 return Err(BinaryReaderError {
802 message: err,
803 offset: self.func_body_offset + self.reader.current_position(),
804 });
805 }
806 Ok(FunctionEnd::Yes) => {
807 self.end_function = true;
808 if !self.reader.eof() {
809 return Err(BinaryReaderError {
810 message: "unexpected end of function",
811 offset: self.func_body_offset + self.reader.current_position(),
812 });
813 }
814 }
815 _ => (),
816 };
817 Ok(op)
818 }
819 }
820
821 /// Test whether the given buffer contains a valid WebAssembly function.
822 /// The resources parameter contains all needed data to validate the operators.
validate_function_body< F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType, >( bytes: &[u8], offset: usize, func_index: u32, resources: &dyn WasmModuleResources< FuncType = F, TableType = T, MemoryType = M, GlobalType = G, >, operator_config: Option<OperatorValidatorConfig>, ) -> Result<()>823 pub fn validate_function_body<
824 F: WasmFuncType,
825 T: WasmTableType,
826 M: WasmMemoryType,
827 G: WasmGlobalType,
828 >(
829 bytes: &[u8],
830 offset: usize,
831 func_index: u32,
832 resources: &dyn WasmModuleResources<
833 FuncType = F,
834 TableType = T,
835 MemoryType = M,
836 GlobalType = G,
837 >,
838 operator_config: Option<OperatorValidatorConfig>,
839 ) -> Result<()> {
840 let operator_config = operator_config.unwrap_or(DEFAULT_OPERATOR_VALIDATOR_CONFIG);
841 let function_body = FunctionBody::new(offset, bytes);
842 let mut locals_reader = function_body.get_locals_reader()?;
843 let local_count = locals_reader.get_count() as usize;
844 if local_count > MAX_WASM_FUNCTION_LOCALS {
845 return Err(BinaryReaderError {
846 message: "locals exceed maximum",
847 offset: locals_reader.original_position(),
848 });
849 }
850 let mut locals: Vec<(u32, Type)> = Vec::with_capacity(local_count);
851 let mut locals_total: usize = 0;
852 for _ in 0..local_count {
853 let (count, ty) = locals_reader.read()?;
854 locals_total =
855 locals_total
856 .checked_add(count as usize)
857 .ok_or_else(|| BinaryReaderError {
858 message: "locals overflow",
859 offset: locals_reader.original_position(),
860 })?;
861 if locals_total > MAX_WASM_FUNCTION_LOCALS {
862 return Err(BinaryReaderError {
863 message: "locals exceed maximum",
864 offset: locals_reader.original_position(),
865 });
866 }
867 locals.push((count, ty));
868 }
869 let operators_reader = function_body.get_operators_reader()?;
870 let func_type_index = resources
871 .func_type_id_at(func_index)
872 // Note: This was an out-of-bounds access before the change to return `Option`
873 // so I assumed it is considered a bug to access a non-existing function
874 // id here and went with panicking instead of returning a proper error.
875 .expect("the function index of the validated function itself is out of bounds");
876 let func_type = resources
877 .type_at(func_type_index)
878 // Note: This was an out-of-bounds access before the change to return `Option`
879 // so I assumed it is considered a bug to access a non-existing function
880 // id here and went with panicking instead of returning a proper error.
881 .expect("the function type indexof the validated function itself is out of bounds");
882 let mut operator_validator = OperatorValidator::new(func_type, &locals, operator_config);
883 let mut eof_found = false;
884 let mut last_op = 0;
885 for item in operators_reader.into_iter_with_offsets() {
886 let (ref op, offset) = item?;
887 match operator_validator
888 .process_operator(op, resources)
889 .map_err(|message| BinaryReaderError { message, offset })?
890 {
891 FunctionEnd::Yes => {
892 eof_found = true;
893 }
894 FunctionEnd::No => {
895 last_op = offset;
896 }
897 }
898 }
899 if !eof_found {
900 return Err(BinaryReaderError {
901 message: "end of function not found",
902 offset: last_op,
903 });
904 }
905 Ok(())
906 }
907
908 /// Test whether the given buffer contains a valid WebAssembly module,
909 /// analogous to WebAssembly.validate in the JS API.
validate(bytes: &[u8], config: Option<ValidatingParserConfig>) -> Result<()>910 pub fn validate(bytes: &[u8], config: Option<ValidatingParserConfig>) -> Result<()> {
911 let mut parser = ValidatingParser::new(bytes, config);
912 let mut parser_input = None;
913 let mut func_ranges = Vec::new();
914 loop {
915 let next_input = parser_input.take().unwrap_or(ParserInput::Default);
916 let state = parser.read_with_input(next_input);
917 match *state {
918 ParserState::EndWasm => break,
919 ParserState::Error(e) => return Err(e),
920 ParserState::BeginFunctionBody { range } => {
921 parser_input = Some(ParserInput::SkipFunctionBody);
922 func_ranges.push(range);
923 }
924 _ => (),
925 }
926 }
927 let operator_config = config.map(|c| c.operator_config);
928 for (i, range) in func_ranges.into_iter().enumerate() {
929 let function_body = range.slice(bytes);
930 let function_index = i as u32 + parser.func_imports_count;
931 validate_function_body(
932 function_body,
933 range.start,
934 function_index,
935 &parser.resources,
936 operator_config,
937 )?;
938 }
939 Ok(())
940 }
941
942 #[test]
test_validate()943 fn test_validate() {
944 assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0], None).is_ok());
945 assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x2, 0x0, 0x0, 0x0], None).is_err());
946 }
947