3 ms·
WASM doesn’t need any sort of “static analysis” to sandbox it in this way. WASM only gets to call the functions exposed by the script that loads the WASM, so if
by johncolanduoni 5y ago
WASM doesn’t need any sort of “static analysis” to sandbox it in this way. WASM only gets to call the functions exposed by the script that loads the WASM, so if you don’t want it to access something you can simply not bother exposing it.
- derefr 5y agoYes and no. There are capabilities that you can only either expose to WASM or not, because they’re simple atomic functions in Javascript land. Dereferencing external Javascript-side objects by a passed-through key, for example. You could in theory write a “fat ISA-op emulation-shim implementation” for that WASM-side operation that has a bunch of Javascript verification code that runs every time the WASM-side op is called, at runtime (like how the Ethereum VM has fat ISA-ops that spend gas/check remaining gas in their impls.) But the resulting runtime likely won’t be performant enough to be a good host for games, if the games make heavy use of that capability, rather than just using it as a one-off boot-time thing. Remember, we want to mostly allow arbitrary code execution here—other than direct attacks on the user or the hosting infrastructure. That probably means that we want to allow the user of the WASM to require (a pre-approved set of) Javascript-side libraries and talk to them. For example, maybe the game wants to talk to Firebase using the Firebase SDK. It should be able to do that. But how do you allow the game’s WASM to talk to the Firebase SDK, efficiently, without allowing the game’s WASM to manipulate the objects of the Firebase SDK into giving it ACE in the host JS environment, outside its sandbox? Static analysis. For the case of a “dereference a key of an remote object” call, just validate that: 1. The string being used as the key in the dereference op is known at compile time (i.e. the dataflow digraph terminating in the WASM “syscall” to the runtime, begins with a load from the static data section of the WASM file; 2. The static-loaded string you discover through this method, isn’t on a blacklist of ECMAScript system properties. (If you want to do something that requires one of those, there’d have to be a separate, much-more-restricted syscall for that, maybe one that does have a fat impl.) The nice thing about this approach, is that it’s the server backend, not the players, who feel the sting of the overhead of checking the file for safety; and then, only once per uploaded program. It’s like putting the uploaded games into a moderation queue, where the “moderator” is a robot with good eyes to spot evil code.
- johncolanduoni 5y agoLast time I checked, all the abilities for directly manipulating JS reference types in WASM had yet to even be deployed outside of developer trials. So there’s a much simpler solution that (a) doesn’t depend on “just” statically analyzing the binary and (b) doesn’t use features that most browsers don’t support. Just expose precisely the Firebase or whatever functionality you wish to through normal WASM imports. No overhead of checking the file for safety at all (beyond the built-in WASM validation and translation of course). And binding the functions for e.g. WebGL directly with a lookup table for passed in object values is going to perform as well as anything else that is actually supported today (and it’s what game engines that support WASM currently use).
- derefr 5y ago> Last time I checked, all the abilities for directly manipulating JS reference types in WASM had yet to even be deployed outside of developer trials. Well, yeah, which means to me that we'd never try to do this today, but rather would do this once that sort of capability exists. (Just like the people who constantly propose multitenant Workers-like hosting within Erlang. Obviously it could work once sandboxing exists within the runtime, but that's not true today.) Note that the whole point of Firebase as a service/library—I picked this example for a reason—is to have a local live Javascript object graph whose state is synchronized over the network to a database somewhere; where you can walk it and read it and change it by doing regular Javascript things to it, as if it were a pure in-memory data structure. If you want to expose that in WASM, you basically need to expose it by exposing Javascript object manipulation semantics to WASM. (Not with WASM holding the objects itself, but rather like any "remote/distributed object" protocol, where WASM holds a handle that references an object, and makes syscalls for dereferencing-get, dereferencing-set, etc., passing that handle.) Without this, what you're exposing isn't really "Firebase" per se, but just a regular database that you send some sort of graph-manipulation queries to. And this is just one example among many of the sorts of arcane Javascript things where, if the hosting platform didn't allow them, then devs would find the hosting platform worthless and never engage with it. This is the whole point of the GGP poster's post. They weren't talking about sandboxing NaCl/ZeroVM-like "the code runs in a sealed ABI abstraction that only exposes the syscalls necessary to read the keyboard/mouse and draw to the screen" games. You can easily do that. It's been done. Developers didn't engage in any meaningful way—nothing like the takeup of Newgrounds. (Heck, it's downright simple to do one of these services yourself: pick an old game console with an HTML5 emulator implementation, e.g. one of the ones used on https://archive.org/details/internetarcade https://archive.org/details/internetarcade, as your abstract-machine runtime. Games, then, are arbitrary homebrew ROMs. Let people upload them; give them a customizable page that embeds them; wrap it in a trailer + payment-wall page ala itch.io if you like. Do fingerprint analysis to reject commercial ROMs. Done. This service could be built for a hackathon. Would anyone care to develop novel games for it? Pretty doubtful.) Instead, what the GGP was talking about sandboxing, is almost-but-not-quite arbitrary Turing machines. Because that's what the Flash games/apps posted to Newgrounds really were, and moreover what the modern track-every-click special-gatcha-for-the-thousandth-player-of-the-day variety always are. They use every capability a computer has, such that "sandboxing" in the sense of removing those capabilities doesn't make sense. You can't restrict what capabilities such programs have access to, without just denying the entire design the software is based around. You can only constrain how the game uses those capabilities. To put that another way: an SMTP server that doesn't let you send mail to certain large email hosting providers is effectively useless. But an SMTP server that doesn't let outgoing messages contain certain words (i.e. has an outbound spam filter) is quite useful. Restricting the what will just turn people away. Restricting the how has no such problem, since certain patterns of data-flow have no other use than to be nefarious. (If you're curious why I'm even talking about WASM at all, then, if I'm not proposing to take advantage of any of the sandboxing WASM offers: it's just because it's much easier to do your static analysis against a symbolic-execution implementation of bytecode VM for a bytecode ISA like WASM; than it is to do symbolic-execution of an interpreted language with complex syntax, like JS. But if you were willing to go down that route, you could totally static-analyze regular JS. Same safety guarantees, plus now the devs get to use regular JS and/or anything that interfaces with it—including the JS-subset textual form of WASM.)