1use crate::error::{Result, Error};
25use std::{collections::HashMap, rc::Rc};
26use codec::{Decode, Encode};
27use tet_core::sandbox as sandbox_primitives;
28use twasmi::{
29 Externals, ImportResolver, MemoryInstance, MemoryRef, Module, ModuleInstance,
30 ModuleRef, RuntimeArgs, RuntimeValue, Trap, TrapKind, memory_units::Pages,
31};
32use tetcore_wasm_interface::{FunctionContext, Pointer, WordSize};
33
34#[derive(Copy, Clone, Debug, PartialEq)]
39pub struct SupervisorFuncIndex(usize);
40
41impl From<SupervisorFuncIndex> for usize {
42 fn from(index: SupervisorFuncIndex) -> Self {
43 index.0
44 }
45}
46
47#[derive(Copy, Clone, Debug, PartialEq)]
51struct GuestFuncIndex(usize);
52
53struct GuestToSupervisorFunctionMapping {
55 funcs: Vec<SupervisorFuncIndex>,
56}
57
58impl GuestToSupervisorFunctionMapping {
59 fn new() -> GuestToSupervisorFunctionMapping {
60 GuestToSupervisorFunctionMapping { funcs: Vec::new() }
61 }
62
63 fn define(&mut self, supervisor_func: SupervisorFuncIndex) -> GuestFuncIndex {
64 let idx = self.funcs.len();
65 self.funcs.push(supervisor_func);
66 GuestFuncIndex(idx)
67 }
68
69 fn func_by_guest_index(&self, guest_func_idx: GuestFuncIndex) -> Option<SupervisorFuncIndex> {
70 self.funcs.get(guest_func_idx.0).cloned()
71 }
72}
73
74struct Imports {
75 func_map: HashMap<(Vec<u8>, Vec<u8>), GuestFuncIndex>,
76 memories_map: HashMap<(Vec<u8>, Vec<u8>), MemoryRef>,
77}
78
79impl ImportResolver for Imports {
80 fn resolve_func(
81 &self,
82 module_name: &str,
83 field_name: &str,
84 signature: &::twasmi::Signature,
85 ) -> std::result::Result<twasmi::FuncRef, twasmi::Error> {
86 let key = (
87 module_name.as_bytes().to_owned(),
88 field_name.as_bytes().to_owned(),
89 );
90 let idx = *self.func_map.get(&key).ok_or_else(|| {
91 twasmi::Error::Instantiation(format!(
92 "Export {}:{} not found",
93 module_name, field_name
94 ))
95 })?;
96 Ok(twasmi::FuncInstance::alloc_host(signature.clone(), idx.0))
97 }
98
99 fn resolve_memory(
100 &self,
101 module_name: &str,
102 field_name: &str,
103 _memory_type: &::twasmi::MemoryDescriptor,
104 ) -> std::result::Result<MemoryRef, twasmi::Error> {
105 let key = (
106 module_name.as_bytes().to_vec(),
107 field_name.as_bytes().to_vec(),
108 );
109 let mem = self.memories_map
110 .get(&key)
111 .ok_or_else(|| {
112 twasmi::Error::Instantiation(format!(
113 "Export {}:{} not found",
114 module_name, field_name
115 ))
116 })?
117 .clone();
118 Ok(mem)
119 }
120
121 fn resolve_global(
122 &self,
123 module_name: &str,
124 field_name: &str,
125 _global_type: &::twasmi::GlobalDescriptor,
126 ) -> std::result::Result<twasmi::GlobalRef, twasmi::Error> {
127 Err(twasmi::Error::Instantiation(format!(
128 "Export {}:{} not found",
129 module_name, field_name
130 )))
131 }
132
133 fn resolve_table(
134 &self,
135 module_name: &str,
136 field_name: &str,
137 _table_type: &::twasmi::TableDescriptor,
138 ) -> std::result::Result<twasmi::TableRef, twasmi::Error> {
139 Err(twasmi::Error::Instantiation(format!(
140 "Export {}:{} not found",
141 module_name, field_name
142 )))
143 }
144}
145
146pub trait SandboxCapabilities: FunctionContext {
150 type SupervisorFuncRef;
152
153 fn invoke(
167 &mut self,
168 dispatch_thunk: &Self::SupervisorFuncRef,
169 invoke_args_ptr: Pointer<u8>,
170 invoke_args_len: WordSize,
171 state: u32,
172 func_idx: SupervisorFuncIndex,
173 ) -> Result<i64>;
174}
175
176pub struct GuestExternals<'a, FE: SandboxCapabilities + 'a> {
181 supervisor_externals: &'a mut FE,
182 sandbox_instance: &'a SandboxInstance<FE::SupervisorFuncRef>,
183 state: u32,
184}
185
186fn trap(msg: &'static str) -> Trap {
187 TrapKind::Host(Box::new(Error::Other(msg.into()))).into()
188}
189
190fn deserialize_result(serialized_result: &[u8]) -> std::result::Result<Option<RuntimeValue>, Trap> {
191 use self::sandbox_primitives::HostError;
192 use tetcore_wasm_interface::ReturnValue;
193 let result_val = std::result::Result::<ReturnValue, HostError>::decode(&mut &serialized_result[..])
194 .map_err(|_| trap("Decoding Result<ReturnValue, HostError> failed!"))?;
195
196 match result_val {
197 Ok(return_value) => Ok(match return_value {
198 ReturnValue::Unit => None,
199 ReturnValue::Value(typed_value) => Some(RuntimeValue::from(typed_value)),
200 }),
201 Err(HostError) => Err(trap("Supervisor function returned sandbox::HostError")),
202 }
203}
204
205impl<'a, FE: SandboxCapabilities + 'a> Externals for GuestExternals<'a, FE> {
206 fn invoke_index(
207 &mut self,
208 index: usize,
209 args: RuntimeArgs,
210 ) -> std::result::Result<Option<RuntimeValue>, Trap> {
211 let index = GuestFuncIndex(index);
213
214 let func_idx = self.sandbox_instance
215 .guest_to_supervisor_mapping
216 .func_by_guest_index(index)
217 .expect(
218 "`invoke_index` is called with indexes registered via `FuncInstance::alloc_host`;
219 `FuncInstance::alloc_host` is called with indexes that was obtained from `guest_to_supervisor_mapping`;
220 `func_by_guest_index` called with `index` can't return `None`;
221 qed"
222 );
223
224 let invoke_args_data: Vec<u8> = args.as_ref()
226 .iter()
227 .cloned()
228 .map(tetcore_wasm_interface::Value::from)
229 .collect::<Vec<_>>()
230 .encode();
231
232 let state = self.state;
233
234 let invoke_args_len = invoke_args_data.len() as WordSize;
237 let invoke_args_ptr = self
238 .supervisor_externals
239 .allocate_memory(invoke_args_len)
240 .map_err(|_| trap("Can't allocate memory in supervisor for the arguments"))?;
241
242 let deallocate = |this: &mut GuestExternals<FE>, ptr, fail_msg| {
243 this
244 .supervisor_externals
245 .deallocate_memory(ptr)
246 .map_err(|_| trap(fail_msg))
247 };
248
249 if self
250 .supervisor_externals
251 .write_memory(invoke_args_ptr, &invoke_args_data)
252 .is_err()
253 {
254 deallocate(self, invoke_args_ptr, "Failed dealloction after failed write of invoke arguments")?;
255 return Err(trap("Can't write invoke args into memory"));
256 }
257
258 let result = self.supervisor_externals.invoke(
259 &self.sandbox_instance.dispatch_thunk,
260 invoke_args_ptr,
261 invoke_args_len,
262 state,
263 func_idx,
264 );
265
266 deallocate(self, invoke_args_ptr, "Can't deallocate memory for dispatch thunk's invoke arguments")?;
267 let result = result?;
268
269 let (serialized_result_val_ptr, serialized_result_val_len) = {
272 let v = result as u64;
274 let ptr = (v as u64 >> 32) as u32;
275 let len = (v & 0xFFFFFFFF) as u32;
276 (Pointer::new(ptr), len)
277 };
278
279 let serialized_result_val = self.supervisor_externals
280 .read_memory(serialized_result_val_ptr, serialized_result_val_len)
281 .map_err(|_| trap("Can't read the serialized result from dispatch thunk"));
282
283 deallocate(self, serialized_result_val_ptr, "Can't deallocate memory for dispatch thunk's result")
284 .and_then(|_| serialized_result_val)
285 .and_then(|serialized_result_val| deserialize_result(&serialized_result_val))
286 }
287}
288
289fn with_guest_externals<FE, R, F>(
290 supervisor_externals: &mut FE,
291 sandbox_instance: &SandboxInstance<FE::SupervisorFuncRef>,
292 state: u32,
293 f: F,
294) -> R
295where
296 FE: SandboxCapabilities,
297 F: FnOnce(&mut GuestExternals<FE>) -> R,
298{
299 let mut guest_externals = GuestExternals {
300 supervisor_externals,
301 sandbox_instance,
302 state,
303 };
304 f(&mut guest_externals)
305}
306
307pub struct SandboxInstance<FR> {
322 instance: ModuleRef,
323 dispatch_thunk: FR,
324 guest_to_supervisor_mapping: GuestToSupervisorFunctionMapping,
325}
326
327impl<FR> SandboxInstance<FR> {
328 pub fn invoke<FE: SandboxCapabilities<SupervisorFuncRef=FR>>(
336 &self,
337 export_name: &str,
338 args: &[RuntimeValue],
339 supervisor_externals: &mut FE,
340 state: u32,
341 ) -> std::result::Result<Option<twasmi::RuntimeValue>, twasmi::Error> {
342 with_guest_externals(
343 supervisor_externals,
344 self,
345 state,
346 |guest_externals| {
347 self.instance
348 .invoke_export(export_name, args, guest_externals)
349 },
350 )
351 }
352
353 pub fn get_global_val(&self, name: &str) -> Option<tetcore_wasm_interface::Value> {
357 let global = self.instance
358 .export_by_name(name)?
359 .as_global()?
360 .get();
361
362 Some(global.into())
363 }
364}
365
366pub enum InstantiationError {
368 EnvironmentDefinitionCorrupted,
371 ModuleDecoding,
373 Instantiation,
376 StartTrapped,
379}
380
381fn decode_environment_definition(
382 raw_env_def: &[u8],
383 memories: &[Option<MemoryRef>],
384) -> std::result::Result<(Imports, GuestToSupervisorFunctionMapping), InstantiationError> {
385 let env_def = sandbox_primitives::EnvironmentDefinition::decode(&mut &raw_env_def[..])
386 .map_err(|_| InstantiationError::EnvironmentDefinitionCorrupted)?;
387
388 let mut func_map = HashMap::new();
389 let mut memories_map = HashMap::new();
390 let mut guest_to_supervisor_mapping = GuestToSupervisorFunctionMapping::new();
391
392 for entry in &env_def.entries {
393 let module = entry.module_name.clone();
394 let field = entry.field_name.clone();
395
396 match entry.entity {
397 sandbox_primitives::ExternEntity::Function(func_idx) => {
398 let externals_idx =
399 guest_to_supervisor_mapping.define(SupervisorFuncIndex(func_idx as usize));
400 func_map.insert((module, field), externals_idx);
401 }
402 sandbox_primitives::ExternEntity::Memory(memory_idx) => {
403 let memory_ref = memories
404 .get(memory_idx as usize)
405 .cloned()
406 .ok_or_else(|| InstantiationError::EnvironmentDefinitionCorrupted)?
407 .ok_or_else(|| InstantiationError::EnvironmentDefinitionCorrupted)?;
408 memories_map.insert((module, field), memory_ref);
409 }
410 }
411 }
412
413 Ok((
414 Imports {
415 func_map,
416 memories_map,
417 },
418 guest_to_supervisor_mapping,
419 ))
420}
421
422pub struct GuestEnvironment {
424 imports: Imports,
425 guest_to_supervisor_mapping: GuestToSupervisorFunctionMapping,
426}
427
428impl GuestEnvironment {
429 pub fn decode<FR>(
433 store: &Store<FR>,
434 raw_env_def: &[u8],
435 ) -> std::result::Result<Self, InstantiationError> {
436 let (imports, guest_to_supervisor_mapping) =
437 decode_environment_definition(raw_env_def, &store.memories)?;
438 Ok(Self {
439 imports,
440 guest_to_supervisor_mapping,
441 })
442 }
443}
444
445#[must_use]
449pub struct UnregisteredInstance<FR> {
450 sandbox_instance: Rc<SandboxInstance<FR>>,
451}
452
453impl<FR> UnregisteredInstance<FR> {
454 pub fn register(self, store: &mut Store<FR>) -> u32 {
456 let instance_idx = store.register_sandbox_instance(self.sandbox_instance);
458 instance_idx
459 }
460}
461
462pub fn instantiate<'a, FE: SandboxCapabilities>(
477 supervisor_externals: &mut FE,
478 dispatch_thunk: FE::SupervisorFuncRef,
479 wasm: &[u8],
480 host_env: GuestEnvironment,
481 state: u32,
482) -> std::result::Result<UnregisteredInstance<FE::SupervisorFuncRef>, InstantiationError> {
483 let module = Module::from_buffer(wasm).map_err(|_| InstantiationError::ModuleDecoding)?;
484 let instance = ModuleInstance::new(&module, &host_env.imports)
485 .map_err(|_| InstantiationError::Instantiation)?;
486
487 let sandbox_instance = Rc::new(SandboxInstance {
488 instance: instance.not_started_instance().clone(),
492 dispatch_thunk,
493 guest_to_supervisor_mapping: host_env.guest_to_supervisor_mapping,
494 });
495
496 with_guest_externals(
497 supervisor_externals,
498 &sandbox_instance,
499 state,
500 |guest_externals| {
501 instance
502 .run_start(guest_externals)
503 .map_err(|_| InstantiationError::StartTrapped)
504 },
505 )?;
506
507 Ok(UnregisteredInstance { sandbox_instance })
508}
509
510pub struct Store<FR> {
514 instances: Vec<Option<Rc<SandboxInstance<FR>>>>,
516 memories: Vec<Option<MemoryRef>>,
517}
518
519impl<FR> Store<FR> {
520 pub fn new() -> Self {
522 Store {
523 instances: Vec::new(),
524 memories: Vec::new(),
525 }
526 }
527
528 pub fn new_memory(&mut self, initial: u32, maximum: u32) -> Result<u32> {
535 let maximum = match maximum {
536 sandbox_primitives::MEM_UNLIMITED => None,
537 specified_limit => Some(Pages(specified_limit as usize)),
538 };
539
540 let mem =
541 MemoryInstance::alloc(
542 Pages(initial as usize),
543 maximum,
544 )?;
545
546 let mem_idx = self.memories.len();
547 self.memories.push(Some(mem));
548 Ok(mem_idx as u32)
549 }
550
551 pub fn instance(&self, instance_idx: u32) -> Result<Rc<SandboxInstance<FR>>> {
558 self.instances
559 .get(instance_idx as usize)
560 .cloned()
561 .ok_or_else(|| "Trying to access a non-existent instance")?
562 .ok_or_else(|| "Trying to access a torndown instance".into())
563 }
564
565 pub fn memory(&self, memory_idx: u32) -> Result<MemoryRef> {
572 self.memories
573 .get(memory_idx as usize)
574 .cloned()
575 .ok_or_else(|| "Trying to access a non-existent sandboxed memory")?
576 .ok_or_else(|| "Trying to access a torndown sandboxed memory".into())
577 }
578
579 pub fn memory_teardown(&mut self, memory_idx: u32) -> Result<()> {
586 match self.memories.get_mut(memory_idx as usize) {
587 None => Err("Trying to teardown a non-existent sandboxed memory".into()),
588 Some(None) => Err("Double teardown of a sandboxed memory".into()),
589 Some(memory) => {
590 *memory = None;
591 Ok(())
592 }
593 }
594 }
595
596 pub fn instance_teardown(&mut self, instance_idx: u32) -> Result<()> {
603 match self.instances.get_mut(instance_idx as usize) {
604 None => Err("Trying to teardown a non-existent instance".into()),
605 Some(None) => Err("Double teardown of an instance".into()),
606 Some(instance) => {
607 *instance = None;
608 Ok(())
609 }
610 }
611 }
612
613 fn register_sandbox_instance(&mut self, sandbox_instance: Rc<SandboxInstance<FR>>) -> u32 {
614 let instance_idx = self.instances.len();
615 self.instances.push(Some(sandbox_instance));
616 instance_idx as u32
617 }
618}