Fix error handling in sandboxing/contracts modules (#744)

* Fix error handling in sandboxing/contracts modules

* Add some docs.

* Add some tests.

* grammar
This commit is contained in:
Sergey Pepyakin
2018-09-19 11:01:25 +03:00
committed by Gav Wood
parent 400a22ebe5
commit 488830e81a
7 changed files with 154 additions and 21 deletions
+106 -9
View File
@@ -335,11 +335,27 @@ impl SandboxInstance {
}
}
/// Error occured during instantiation of a sandboxed module.
pub enum InstantiationError {
/// Something wrong with the environment definition. It either can't
/// be decoded, have a reference to a non-existent or torn down memory instance.
EnvironmentDefintionCorrupted,
/// Provided module isn't recognized as a valid webassembly binary.
ModuleDecoding,
/// Module is a well-formed webassembly binary but could not be instantiated. This could
/// happen because, e.g. the module imports entries not provided by the environment.
Instantiation,
/// Module is well-formed, instantiated and linked, but while executing the start function
/// a trap was generated.
StartTrapped,
}
fn decode_environment_definition(
raw_env_def: &[u8],
memories: &[Option<MemoryRef>],
) -> Result<(Imports, GuestToSupervisorFunctionMapping), UserError> {
let env_def = sandbox_primitives::EnvironmentDefinition::decode(&mut &raw_env_def[..]).ok_or_else(|| UserError("Sandbox error"))?;
) -> Result<(Imports, GuestToSupervisorFunctionMapping), InstantiationError> {
let env_def = sandbox_primitives::EnvironmentDefinition::decode(&mut &raw_env_def[..])
.ok_or_else(|| InstantiationError::EnvironmentDefintionCorrupted)?;
let mut func_map = HashMap::new();
let mut memories_map = HashMap::new();
@@ -359,8 +375,8 @@ fn decode_environment_definition(
let memory_ref = memories
.get(memory_idx as usize)
.cloned()
.ok_or_else(|| UserError("Sandbox error"))?
.ok_or_else(|| UserError("Sandbox error"))?;
.ok_or_else(|| InstantiationError::EnvironmentDefintionCorrupted)?
.ok_or_else(|| InstantiationError::EnvironmentDefintionCorrupted)?;
memories_map.insert((module, field), memory_ref);
}
}
@@ -395,12 +411,12 @@ pub fn instantiate<FE: SandboxCapabilities + Externals>(
wasm: &[u8],
raw_env_def: &[u8],
state: u32,
) -> Result<u32, UserError> {
) -> Result<u32, InstantiationError> {
let (imports, guest_to_supervisor_mapping) =
decode_environment_definition(raw_env_def, &supervisor_externals.store().memories)?;
let module = Module::from_buffer(wasm).map_err(|_| UserError("Sandbox error"))?;
let instance = ModuleInstance::new(&module, &imports).map_err(|_| UserError("Sandbox error"))?;
let module = Module::from_buffer(wasm).map_err(|_| InstantiationError::ModuleDecoding)?;
let instance = ModuleInstance::new(&module, &imports).map_err(|_| InstantiationError::Instantiation)?;
let sandbox_instance = Rc::new(SandboxInstance {
// In general, it's not a very good idea to use `.not_started_instance()` for anything
@@ -418,14 +434,14 @@ pub fn instantiate<FE: SandboxCapabilities + Externals>(
|guest_externals| {
instance
.run_start(guest_externals)
.map_err(|_| UserError("Sandbox error"))
.map_err(|_| InstantiationError::StartTrapped)
},
)?;
// At last, register the instance.
let instance_idx = supervisor_externals
.store_mut()
.register_sandbox_instance(sandbox_instance);
Ok(instance_idx)
}
@@ -674,4 +690,85 @@ mod tests {
vec![1],
);
}
#[test]
fn unlinkable_module() {
let mut ext = TestExternalities::default();
let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm");
let code = wabt::wat2wasm(r#"
(module
(import "env" "non-existent" (func))
(func (export "call")
)
)
"#).unwrap();
assert_eq!(
WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(),
vec![1],
);
}
#[test]
fn corrupted_module() {
let mut ext = TestExternalities::default();
let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm");
// Corrupted wasm file
let code = &[0, 0, 0, 0, 1, 0, 0, 0];
assert_eq!(
WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", code).unwrap(),
vec![1],
);
}
#[test]
fn start_fn_ok() {
let mut ext = TestExternalities::default();
let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm");
let code = wabt::wat2wasm(r#"
(module
(func (export "call")
)
(func $start
)
(start $start)
)
"#).unwrap();
assert_eq!(
WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(),
vec![0],
);
}
#[test]
fn start_fn_traps() {
let mut ext = TestExternalities::default();
let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm");
let code = wabt::wat2wasm(r#"
(module
(func (export "call")
)
(func $start
unreachable
)
(start $start)
)
"#).unwrap();
assert_eq!(
WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(),
vec![2],
);
}
}
+15 -3
View File
@@ -344,7 +344,14 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
5
})
},
ext_sandbox_instantiate(dispatch_thunk_idx: usize, wasm_ptr: *const u8, wasm_len: usize, imports_ptr: *const u8, imports_len: usize, state: usize) -> u32 => {
ext_sandbox_instantiate(
dispatch_thunk_idx: usize,
wasm_ptr: *const u8,
wasm_len: usize,
imports_ptr: *const u8,
imports_len: usize,
state: usize
) -> u32 => {
let wasm = this.memory.get(wasm_ptr, wasm_len as usize).map_err(|_| UserError("Sandbox error"))?;
let raw_env_def = this.memory.get(imports_ptr, imports_len as usize).map_err(|_| UserError("Sandbox error"))?;
@@ -357,9 +364,14 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
.clone()
};
let instance_idx = sandbox::instantiate(this, dispatch_thunk, &wasm, &raw_env_def, state)?;
let instance_idx_or_err_code =
match sandbox::instantiate(this, dispatch_thunk, &wasm, &raw_env_def, state) {
Ok(instance_idx) => instance_idx,
Err(sandbox::InstantiationError::StartTrapped) => sandbox_primitives::ERR_EXECUTION,
Err(_) => sandbox_primitives::ERR_MODULE,
};
Ok(instance_idx as u32)
Ok(instance_idx_or_err_code as u32)
},
ext_sandbox_instance_teardown(instance_idx: u32) => {
this.sandbox_store.instance_teardown(instance_idx)?;