4 ms·
It seems they aimed to answer the question: What are the consequences of limiting the WA spec to only try to sandbox the WA binary from outside memory, and not
by infogulch 6y ago
It seems they aimed to answer the question: What are the consequences of limiting the WA spec to only try to sandbox the WA binary from outside memory, and not try to prevent it from exploiting itself? The answer they got was that yes, a WA binary may be capable of exploiting itself. I think this is an interesting and valuable result, but I don't think the result is surprising, or that it invalidates the design of WA. The outputs from WA are not guaranteed to be what you expect. Or put another way: C is still C. I wonder if such a vulnerability could be found in a program written in safe Rust.
Notably, they don't appear to even try to break the WA-host memory barrier, which I actually find to be a validation of the core design goal of WebAssembly: isolate the damage a vulnerable program can inflict to the memory space (and thus also output) of that program. Protect the host from the program, but not the program from itself. Also, maybe don't dump WA output you can't validate directly into DOM.
- saagarjha 6y agoRust would have to change some things, certainly. Signal handlers won’t cut it anymore, for example.
- est31 6y agoIs this a limitation of the spec or of the implementations? For example, Figure 1 in the paper mentions ASLR as missing in wasm but can't a wasm JIT choose to deploy ASLR if it wants to? Edit: I read the section 3.3 now and it seems that the stack and the heap live in the same linear memory, which is obviously bad. But function addresses can still be randomly offset, no? Also the paper admits that security has been an important component of the design of wasm: "The design of WebAssembly includes various features to ensure binary security. For example, the memory maintained by a WebAssembly program is separated from its code, the execution stack, and the data structures of the underlying VM. To prevent type-related crashes and attacks, binaries are designed to be easily type-checked,which they are statically before execution. Moreoever, WebAssembly programs can only jump to designated code locations,a form of fault isolation that prevents many classic control flow attacks."
- AgentME 6y agoWebAssembly 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).
- angrygoat 6y agoWASM and the surrounding Javascript model offer a lot of opportunities to minimise the damage if something gets exploited. Say you are running OCR via some C library you have compiled to WASM: wrap that functionality up with an interface, compile that to WASM, and only pass it the image data you're happy for it to see. If someone exploits that binary with a malicious image, there's nothing inside the container except the code and the image itself, so hopefully the damage is contained. If folks start compiling large amounts of their functionality into one single chunk of WASM, which has a complex interface with the DOM/JS, then I can see how these exploits could become an issue.
- rini17 6y agoEven then. If the input images are from untrusted source, you need to scrupulously treat the OCR output as untrusted too, and that it is actually OCRing and not mining crypto (say, using image library exploit + OCR math library functions), etc. etc.
- angrygoat 6y agoTrue, but there's not much point mining for crypto if the WASM module's gateway to the DOM/JS/... doesn't let you export the result.
- maxgraey 6y ago> If folks start compiling large amounts of their functionality into one single chunk of WASM WebAssembly multi memory proposal and nanoprocesses (one of WASI initiative) should solve all this problems as well
- maxgraey 6y agoBut for now dynamic linking of two wasm modules is not even possible
- daniellehmann 6y ago> some C library you have compiled to WASM: wrap that functionality up with an interface, compile that to WASM, and only pass it the image data you're happy for it to see That is good advice. Separately compiling C code into individual modules with small interfaces and as little host imports as possible does make exploitation harder. This is also one of the propositions we make in the mitigations section of the paper. > If folks start compiling large amounts of their functionality into one single chunk of WASM However, I also believe that is what will happen soon. Many people are eager to use WebAssembly for more parts of the front-end (and also because they want to develop in Go, Rust, etc., see the increasing number of DOM-libraries for WebAssembly). With more code being linked into a single WebAssembly module, it becomes more important to look into security inside a single WebAssembly module.
- daniellehmann 6y agoI am not sure I understand the sentence "limiting the WA spec to only try to sandbox the WA binary from outside memory". I would not say that we (as in: the authors of the paper) are trying to limit the spec, or that we tried to only look into those parts of the spec that are not concerned with security. (I hope I do not misunderstand your point.) The spec/language/memory organization of WebAssembly really does not do much to provide security inside a WebAssembly program's own memory. I do agree with you, however, that our findings do not invalidate the overall design of WebAssembly. I really like the simplicity and generality of WebAssembly, and the technical (and social) achievement of having a "universal bytecode" supported in four different JavaScript engines (and some standalone VMs), on top of several different hardware architectures (x86, x86-64, ARM, etc.), with good performance, etc. I also think "host security" (which we are not really looking into) is solid, with two qualifications: * In browsers, WebAssembly is sandboxed like JavaScript is, which is well tested. * In other host environments (in particular, standalone VMs) the story might be different. It is hard to make any general statements about host security without talking about the concrete host at hand. > they don't appear to even try to break the WA-host memory barrier That's correct. However, just because we did not try, I would not say that breaking out of WebAssembly memory is impossible. But those attacks will be engine-specific. There have been some attacks against WebAssembly implementations (https://labs.f-secure.com/assets/BlogFiles/apple-safari-wasm-section-vuln-write-up-2018-04-16.pdf https://labs.f-secure.com/assets/BlogFiles/apple-safari-wasm..., https://googleprojectzero.blogspot.com/2018/08/the-problems-and-promise-of-webassembly.html https://googleprojectzero.blogspot.com/2018/08/the-problems-...) and surely will be more; a VM implementation is non-trivial with potential bugs after all. > don't dump WA output you can't validate directly into DOM Exactly, that is one of the problems with shortened statements such as "WebAssembly has great security". At the very least, one should be aware that inside WebAssembly's linear memory, many common security features are absent. This is relevant in particular when you link together large applications (including legacy C and C++ code) into a single WebAssembly binary, that all share the same linear memory.
- infogulch 6y agoThanks for responding, and for this interesting work! I think you understand the thrust of my point. It might have been better stated like: > Designers of the WebAssembly spec explicitly chose to scope it's goal of a 'secure sandbox' to only include securing the host's memory from the WebAssembly VM. They have succeeded in this goal (modulo implementation deficiencies). > However, they left open the question of how a developer might ensure the correctness of their program running in the sandbox. This paper explores the consequences of that original design goal for such a developer, and concludes that all the regular binary exploit mitigations may still be useful for ensuring program correctness. I agree with your qualifications; sprinkling some WebAssembly on your app doesn't magically make security problems in the original code go away. If it's vulnerable it can still do damage to everything you give it access to.