6 ms·
> "it all must live inside the sandbox provided by the runtime." Processes with a strong user model are already one of the most effective isolation mechanisms
by mooman219 8y ago
> "it all must live inside the sandbox provided by the runtime."
Processes with a strong user model are already one of the most effective isolation mechanisms in an operating system. Continually hardening your VM/runtime that was ported into the kernel, in my opinion, either results in either you building a microkernel or recreating the userspace/kernel separation that already exists?
- _wmd 8y agoParent comment refers to running buggy code in ring 0, however in a design like wasmjit, that code would be compiled first to wasm, and the actual code running in-kernel is a derivation that includes bounds checking on at least memory operations. The original code never "runs" in ring 0, what runs is a derivation that includes a software equivalent of the hardware isolation we're used to and have relied on for the past 20 years. While I haven't studied wasmjit, the most obvious implementation is to run system calls naturally, with a global "struct task" existing as before that defines the semantics of the current context, including details like the current UID and capability mask - in other words, without effort, read() and open() could be made to behave identically to before, it's just that the caller now lives in a software sandbox rather than a hardware sandbox, and most/all expensive hardware reconfiguration was avoided
- comesee 8y agoI read through it and this is indeed how it works. Wasm as a language provides the restrictions that the MMU provides for machine code. You can't read from/write to arbitrary pointers in wasm.
- pjmlp 8y agoWASM does not do bounds checking on pointer data.
- comesee 8y agoIt does
- pjmlp 8y agoIt does not, something like char buff[100]; char func(int idx) { char *ptr = buff; return ptr[idx]; } int main (void) { printf("%c", func(200)); return 0; } Compiles nicely to something like this (module (type $FUNCSIG$ii (func (param i32) (result i32))) (import "env" "putchar" (func $putchar (param i32) (result i32))) (table 0 anyfunc) (memory $0 1) (export "memory" (memory $0)) (export "func" (func $func)) (export "main" (func $main)) (func $func (; 1 ;) (param $0 i32) (result i32) (i32.load8_s (i32.add (get_local $0) (i32.const 16) ) ) ) (func $main (; 2 ;) (result i32) (drop (call $putchar (i32.load8_s offset=216 (i32.const 0) ) ) ) (i32.const 0) ) ) Which will gladly blow up, or not, when i32.load8_s gets called. https://webassembly.studio/ https://webassembly.studio/
- comesee 8y agoThe load8_s instruction will check that the computed offset into the memory of size 64KB (1 wasm page) does not index past the bounds of 64KB. If it does, the program will trap.
- pjmlp 8y agoWhich will not work on the provided example, thus leading to memory corruption. Where is the WebAssembly implementation that traps on my example?
- comesee 8y agoWebAssembly protects the host from memory corruption by the user module. To do this it does a bounds check before executing the load. It does not protect a user module from itself. It does not change the semantics of C. Relevant documentation http://webassembly.github.io/spec/core/syntax/instructions.html#syntax-instr-memory http://webassembly.github.io/spec/core/syntax/instructions.h...