Skip to content
Snippets Groups Projects
Commit 270d0186 authored by Sergey Pepyakin's avatar Sergey Pepyakin Committed by Gav Wood
Browse files

Refine sandbox errors (#860)

parent 35f3fe7e
Branches
No related merge requests found
...@@ -181,21 +181,21 @@ pub struct GuestExternals<'a, FE: SandboxCapabilities + Externals + 'a> { ...@@ -181,21 +181,21 @@ pub struct GuestExternals<'a, FE: SandboxCapabilities + Externals + 'a> {
state: u32, state: u32,
} }
fn trap() -> Trap { fn trap(msg: &'static str) -> Trap {
TrapKind::Host(Box::new(UserError("Sandbox error"))).into() TrapKind::Host(Box::new(UserError(msg))).into()
} }
fn deserialize_result(serialized_result: &[u8]) -> Result<Option<RuntimeValue>, Trap> { fn deserialize_result(serialized_result: &[u8]) -> Result<Option<RuntimeValue>, Trap> {
use self::sandbox_primitives::{HostError, ReturnValue}; use self::sandbox_primitives::{HostError, ReturnValue};
let result_val = Result::<ReturnValue, HostError>::decode(&mut &serialized_result[..]) let result_val = Result::<ReturnValue, HostError>::decode(&mut &serialized_result[..])
.ok_or_else(|| trap())?; .ok_or_else(|| trap("Decoding Result<ReturnValue, HostError> failed!"))?;
match result_val { match result_val {
Ok(return_value) => Ok(match return_value { Ok(return_value) => Ok(match return_value {
ReturnValue::Unit => None, ReturnValue::Unit => None,
ReturnValue::Value(typed_value) => Some(RuntimeValue::from(typed_value)), ReturnValue::Value(typed_value) => Some(RuntimeValue::from(typed_value)),
}), }),
Err(HostError) => Err(trap()), Err(HostError) => Err(trap("Supervisor function returned sandbox::HostError")),
} }
} }
...@@ -257,7 +257,8 @@ impl<'a, FE: SandboxCapabilities + Externals + 'a> Externals for GuestExternals< ...@@ -257,7 +257,8 @@ impl<'a, FE: SandboxCapabilities + Externals + 'a> Externals for GuestExternals<
let len = (v & 0xFFFFFFFF) as u32; let len = (v & 0xFFFFFFFF) as u32;
(ptr, len) (ptr, len)
} }
_ => return Err(trap()), Ok(_) => return Err(trap("Supervisor function returned unexpected result!")),
Err(_) => return Err(trap("Supervisor function trapped!")),
}; };
let serialized_result_val = self.supervisor_externals let serialized_result_val = self.supervisor_externals
...@@ -474,7 +475,12 @@ impl Store { ...@@ -474,7 +475,12 @@ impl Store {
}; };
let mem = let mem =
MemoryInstance::alloc(Pages(initial as usize), maximum).map_err(|_| UserError("Sandbox error"))?; MemoryInstance::alloc(
Pages(initial as usize),
maximum,
)
.map_err(|_| UserError("Sandboxed memory allocation error"))?;
let mem_idx = self.memories.len(); let mem_idx = self.memories.len();
self.memories.push(Some(mem)); self.memories.push(Some(mem));
Ok(mem_idx as u32) Ok(mem_idx as u32)
...@@ -490,8 +496,8 @@ impl Store { ...@@ -490,8 +496,8 @@ impl Store {
self.instances self.instances
.get(instance_idx as usize) .get(instance_idx as usize)
.cloned() .cloned()
.ok_or_else(|| UserError("Sandbox error"))? .ok_or_else(|| UserError("Trying to access a non-existent instance"))?
.ok_or_else(|| UserError("Sandbox error")) .ok_or_else(|| UserError("Trying to access a torndown instance"))
} }
/// Returns reference to a memory instance by `memory_idx`. /// Returns reference to a memory instance by `memory_idx`.
...@@ -499,35 +505,47 @@ impl Store { ...@@ -499,35 +505,47 @@ impl Store {
/// # Errors /// # Errors
/// ///
/// Returns `Err` If `memory_idx` isn't a valid index of an memory or /// Returns `Err` If `memory_idx` isn't a valid index of an memory or
/// memory is already torndown. /// if memory has been torn down.
pub fn memory(&self, memory_idx: u32) -> Result<MemoryRef, UserError> { pub fn memory(&self, memory_idx: u32) -> Result<MemoryRef, UserError> {
self.memories self.memories
.get(memory_idx as usize) .get(memory_idx as usize)
.cloned() .cloned()
.ok_or_else(|| UserError("Sandbox error"))? .ok_or_else(|| UserError("Trying to access a non-existent sandboxed memory"))?
.ok_or_else(|| UserError("Sandbox error")) .ok_or_else(|| UserError("Trying to access a torndown sandboxed memory"))
} }
/// Teardown the memory at the specified index. /// Tear down the memory at the specified index.
/// ///
/// # Errors /// # Errors
/// ///
/// Returns `Err` if `memory_idx` isn't a valid index of an memory. /// Returns `Err` if `memory_idx` isn't a valid index of an memory or
/// if it has been torn down.
pub fn memory_teardown(&mut self, memory_idx: u32) -> Result<(), UserError> { pub fn memory_teardown(&mut self, memory_idx: u32) -> Result<(), UserError> {
if memory_idx as usize >= self.memories.len() { match self.memories.get_mut(memory_idx as usize) {
return Err(UserError("Sandbox error")); None => Err(UserError("Trying to teardown a non-existent sandboxed memory")),
Some(None) => Err(UserError("Double teardown of a sandboxed memory")),
Some(memory) => {
*memory = None;
Ok(())
}
} }
self.memories[memory_idx as usize] = None;
Ok(())
} }
/// Teardown the instance at the specified index. /// Tear down the instance at the specified index.
///
/// # Errors
///
/// Returns `Err` if `instance_idx` isn't a valid index of an instance or
/// if it has been torn down.
pub fn instance_teardown(&mut self, instance_idx: u32) -> Result<(), UserError> { pub fn instance_teardown(&mut self, instance_idx: u32) -> Result<(), UserError> {
if instance_idx as usize >= self.instances.len() { match self.instances.get_mut(instance_idx as usize) {
return Err(UserError("Sandbox error")); None => Err(UserError("Trying to teardown a non-existent instance")),
Some(None) => Err(UserError("Double teardown of an instance")),
Some(instance) => {
*instance = None;
Ok(())
}
} }
self.instances[instance_idx as usize] = None;
Ok(())
} }
fn register_sandbox_instance(&mut self, sandbox_instance: Rc<SandboxInstance>) -> u32 { fn register_sandbox_instance(&mut self, sandbox_instance: Rc<SandboxInstance>) -> u32 {
......
...@@ -352,15 +352,18 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, ...@@ -352,15 +352,18 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
imports_len: usize, imports_len: usize,
state: usize state: usize
) -> u32 => { ) -> u32 => {
let wasm = this.memory.get(wasm_ptr, wasm_len as usize).map_err(|_| UserError("Sandbox error"))?; let wasm = this.memory.get(wasm_ptr, wasm_len as usize)
let raw_env_def = this.memory.get(imports_ptr, imports_len as usize).map_err(|_| UserError("Sandbox error"))?; .map_err(|_| UserError("OOB while ext_sandbox_instantiate: wasm"))?;
let raw_env_def = this.memory.get(imports_ptr, imports_len as usize)
.map_err(|_| UserError("OOB while ext_sandbox_instantiate: imports"))?;
// Extract a dispatch thunk from instance's table by the specified index. // Extract a dispatch thunk from instance's table by the specified index.
let dispatch_thunk = { let dispatch_thunk = {
let table = this.table.as_ref().ok_or_else(|| UserError("Sandbox error"))?; let table = this.table.as_ref()
.ok_or_else(|| UserError("Runtime doesn't have a table; sandbox is unavailable"))?;
table.get(dispatch_thunk_idx) table.get(dispatch_thunk_idx)
.map_err(|_| UserError("Sandbox error"))? .map_err(|_| UserError("dispatch_thunk_idx is out of the table bounds"))?
.ok_or_else(|| UserError("Sandbox error"))? .ok_or_else(|| UserError("dispatch_thunk_idx points on an empty table entry"))?
.clone() .clone()
}; };
...@@ -382,17 +385,17 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, ...@@ -382,17 +385,17 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
trace!(target: "sr-sandbox", "invoke, instance_idx={}", instance_idx); trace!(target: "sr-sandbox", "invoke, instance_idx={}", instance_idx);
let export = this.memory.get(export_ptr, export_len as usize) let export = this.memory.get(export_ptr, export_len as usize)
.map_err(|_| UserError("Sandbox error")) .map_err(|_| UserError("OOB while ext_sandbox_invoke: export"))
.and_then(|b| .and_then(|b|
String::from_utf8(b) String::from_utf8(b)
.map_err(|_| UserError("Sandbox error")) .map_err(|_| UserError("export name should be a valid utf-8 sequence"))
)?; )?;
// Deserialize arguments and convert them into wasmi types. // Deserialize arguments and convert them into wasmi types.
let serialized_args = this.memory.get(args_ptr, args_len as usize) let serialized_args = this.memory.get(args_ptr, args_len as usize)
.map_err(|_| UserError("Sandbox error"))?; .map_err(|_| UserError("OOB while ext_sandbox_invoke: args"))?;
let args = Vec::<sandbox_primitives::TypedValue>::decode(&mut &serialized_args[..]) let args = Vec::<sandbox_primitives::TypedValue>::decode(&mut &serialized_args[..])
.ok_or_else(|| UserError("Sandbox error"))? .ok_or_else(|| UserError("Can't decode serialized arguments for the invocation"))?
.into_iter() .into_iter()
.map(Into::into) .map(Into::into)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
...@@ -406,11 +409,11 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, ...@@ -406,11 +409,11 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
// Serialize return value and write it back into the memory. // Serialize return value and write it back into the memory.
sandbox_primitives::ReturnValue::Value(val.into()).using_encoded(|val| { sandbox_primitives::ReturnValue::Value(val.into()).using_encoded(|val| {
if val.len() > return_val_len as usize { if val.len() > return_val_len as usize {
Err(UserError("Sandbox error"))?; Err(UserError("Return value buffer is too small"))?;
} }
this.memory this.memory
.set(return_val_ptr, val) .set(return_val_ptr, val)
.map_err(|_| UserError("Sandbox error"))?; .map_err(|_| UserError("Return value buffer is OOB"))?;
Ok(sandbox_primitives::ERR_OK) Ok(sandbox_primitives::ERR_OK)
}) })
} }
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment