3 ms·
WebAssembly has a stack that lives separately from the linear memory, but C++ compiled to WebAssembly generally manages its own parallel "shadow stack" in linea
by AgentME 6y ago
WebAssembly has a stack that lives separately from the linear memory, but C++ compiled to WebAssembly generally manages its own parallel "shadow stack" in linear memory that it keeps some of its stack variables inside. (I believe you can't have pointers into the WebAssembly stack, so anything that might need to be pointed to can't live in it.)
Because the shadow stack is created and managed by the WebAssembly binary itself, it would be its responsibility to add protections like stack protectors or ASLR on it within the linear memory if it wants them. A WebAssembly JIT isn't ever going to touch the linear memory in a way the binary doesn't specify.
>But function addresses can still be randomly offset, no?
No, functions have fixed indexes in a WebAssembly binary. You can't dynamically reassign the indexes at runtime.
You do have the benefit that if your program tries to jump to a function index chosen by an attacker, the attacker can only jump to a function with a compatible type signature. The attacker can't do anything too clever like jumping partway into an arbitrary function, jumping into attacker-written code in the mutable linear memory, or queuing up a series of return addresses to pull off return-oriented-programming.
- daniellehmann 6y agoExcellent explanations. > C++ compiled to WebAssembly generally manages its own parallel "shadow stack" in linear memory In the paper, we call the compiler-organized stack in linear memory the "unmanaged stack", to differentiate it from the "evaluation stack" (WebAssembly is a stack-based VM, so this contains arguments and results of instructions) and the "managed call stack" (contains call frames, return addresses, local variables. Managed by the VM, cannot be inspected explicitly by WebAssembly instructions). > attacker can only jump to a function with a compatible type signature This is true, but note that WebAssembly types are fairly low-level. That is, there are only four primitive types (i32/i64, f32/f64) and, e.g., a C function that takes a string (char *) and a size_t would be type-compatible with a function that takes a signed int and a struct pointer (all those four types map to the same Wasm type: i32).