5 ms·
It'd be good to raise the priority of process-wide WX and design out RCEs of this type once and for all. I am disappointed that Wasm is on the exploit chain for
by titzer 6y ago
It'd be good to raise the priority of process-wide WX and design out RCEs of this type once and for all. I am disappointed that Wasm is on the exploit chain for a bug like this, as I still feel responsible in some way. I know team priorities change, but this one I pushed hard for commitment on before I left.
- v8dev123 6y agoAaaaaand It's not the first time WASM seen in [0] wild. [0] https://bugs.chromium.org/p/chromium/issues/detail?id=835887 https://bugs.chromium.org/p/chromium/issues/detail?id=835887
- titzer 6y agoYeah. And it's not even bugs in the Wasm engine that are the problem; the RWX memory for Wasm JIT code makes all other bugs into potential RCE bugs. It must be banished! :)
- rkangel 6y agoHaving worked in other spaces ensuring W^X on the basis that there is no good reason for it, the only exception is usually "because I need to code generate". How do you even go about getting rid of WRX in a JIT? Do you generate and then remove W?
- 0xC0ncord 6y agoYou pretty much can't, because once memory has been written to at runtime it is assumed to be untrusted. JIT in and of itself is a W^X violation, so the only real solution is to not use it when security over performance is preferred.
- baybal2 6y agoRemove support for raw data types from JS. Remove Array buffers, remove blob support, remove anything which can be used to assembly a continuous binary without passing some sanitation.
- wizzwizz4 6y agoThat isn't sufficient. You know why? exploit("X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*") Okay, so we remove strings. Good thing the in-memory object format isn't known by the atta– wait. Okay, never mind; we can get rid of objects too. And bignums, while we're at it; that leaves us just with bog-standard floating-point integer primitives. Which are stored in a JavaScript call frame. Oops.
- baybal2 6y ago1. String are not executable code 2. Can be sanitised to be valid UTF-16 3. Can be intentionally mangled in memory to prevent abuse
- wizzwizz4 6y ago1. This one is. 2. Won't help. 3. Simply reverse, or make use of, the mangling.
- baybal2 6y ago> 1. This one is. I can check browser memory with a profiler and see if this page is marked as executable. It would not be.
- sfink 6y agoArrayBuffers aren't meant to be executable code either. JS strings are not UTF-16, they are 16-bit chunks of (potentially) nonsense, and enforcing valid UTF-16 would break quite a few existing uses. For example, anything that stores encrypted data in a string. Which "shouldn't" be done, that should be a Uint8Array, but existing APIs basically force you to do it. And there's such a thing as backwards compatibility. Your 3rd point is much more feasible. I doubt any "real" mangling would be good enough from a performance standpoint while still being too difficult for attackers to use. But I could imagine eg breaking any invalid UTF-16/UTF-8 string up into separate rope nodes, maybe even ensuring the nodes don't get allocated too close to each other and/or injecting disrupting hardcoded bytes in between them. (I work on SpiderMonkey, the Firefox JS engine, and we do at least make sure to allocate string data in a separate part of the heap from everything else.)
- titzer 6y agoIn V8, JITed JavaScript code is never writable and executable at the same time; the JIT writes into a buffer, then quiesces JS execution, then copies/flips permissions, then starts running JS code again. In the Wasm engine inside of V8, the code is writable and executable at the same time because the JIT uses multiple concurrent threads in the background during execution and incrementally commits new JITed code as it is finished. (And, funnily enough, this performance optimization is mostly for asm.js code, which is verified and internally translated to Wasm, to be compiled and executed by the Wasm engine). The long-term holy grail is to move the JIT compiler entirely to another process, so only that process has write permissions, and the renderer process (where Wasm and JS execute) has only R and execute permissions, and they used shared memory underneath.