11 ms·
WebAssembly doesn’t make unsafe languages safe
- deleted 8y ago[deleted]
- deleted 8y ago[deleted]
- dmitrygr 8y agothis is complete nonsense. A normal c program running on a modern operating system has the mmu control what memory it can access. So, Web assembly's "just a block of memory" is no better - it is the same.
- sitkack 8y agoCorrect. A normal C program has full reign over the entire process memory space. A wasm program only has access to the call interface provided to it and its linear memory region allocated to it. The guarantees are much different and greatly in favor of wasm. In wasm the stack and the code segments are off limits.
- repsilat 8y ago"Full rein". And the C heap is typically a linear memory region (that grows monotonically) isn't it?
- conradev 8y agoThe process’ address space includes more than just malloc zones: it includes the code of the running process, the stacks for all of the running threads, linked libraries and their imported functions, etc.
- slededit 8y agobrk does grow linearly (a holdover from the days of segmentation). But malloc may well allocate chunks of virtual memory for large allocations. Windows doesn't have a brk equivalent and the underlying heap is fully implemented via VirtualAlloc.
- repsilat 8y agoFair, but I think this all amounts to "A linear patch of memory is fine primitive to build an allocator or standard library on." The "not faulting on address zero" thing is interesting but not crazy -- only broken programs will break.
- slededit 8y agoWhile you can build it that way it is not at all a good way to do it. You lose all the benefits of paging when handling fragmentation - you basically will never be able to shrink the data segment on most practical programs - and therefore never be able to return memory to the operating system. brk is an ancient holdover from when memory protection was done via segmentation. Paging eliminates the need for this historical misfeature. I'm a bit sad WASM propagated it further into modern systems.
- repsilat 8y agoIsn't paging orthogonal to using brk? Or is "paging" something more specific than "virtual memory is handled by the OS in big chunks"? I guess your allocator can try its best to prevent fragmentation, but you're right that returning memory to the OS isn't going to happen without explicit compaction (which nobody in native code is going to do.) Dunno if anyone ever expects memory use to go down though. (Is less true than it used to be? -- I guess we used to make big swap files and now that's less fashionable.) I guess if it's not too much more of a burden on the OS to make it keep track of a Swiss cheese virtual memory allocation then it is useful.
- slededit 8y ago
- kllrnohj 8y agoYou missed the author's point by miles. C only has access to its process space as does WASM. WASM's only improvement is it makes stack smashing bugs harder (which ironically makes real security worse as it means you can't use retpoline, but let's ignore that for now) HOWEVER it gives up on using guard pages and address randomization (systemic preventions against common bugs like buffer overflows), making WASM in practice less safe than C. WASM is only safer for the host embedding untrusted code. For trusted code, though, it's across the board worse in every way - including security. Which shouldn't be all that contentious of a statement since WASM had no goals or intentions to ever replace trusted native code execution. That's not a thing it tries to do, and it shouldn't be a surprise that it didn't do it.
- monocasa 8y ago> which ironically makes real security worse as it means you can't use retpoline Why wouldn't the WASM JIT retpoline all code (probably only if the underlying processor needs it) rather than relying on the guest programs to do it themselves. > HOWEVER it gives up on using guard pages and address randomization (systemic preventions against common bugs like buffer overflows), making WASM in practice less safe than C. Once again, wouldn't the JIT be able to enforce this at runtime? It's not like WASM binaries are referencing raw address offsets.
- kllrnohj 8y ago> Why wouldn't the WASM JIT retpoline all code (probably only if the underlying processor needs it) rather than relying on the guest programs to do it themselves. Possible, but is that then a runtime option in the WASM header? How does it know if the program needs the cost of retpoline or not? And how can a program ensure that it's getting such mitigations when it needs them? > Once again, wouldn't the JIT be able to enforce this at runtime? The JIT has no insight into the app's malloc/free usage, so no, it can't. There is no system allocator in WASM, just a big chunk of linear memory that the app does whatever it wants with. For an actual case study in why this is risky all you have to do is look at OpenSSL's heartbleed. If it had been using the system's malloc/free (which WASM doesn't have) instead of using its internal free lists then heartbleed largely wouldn't have existed on platforms like OpenBSD.
- deleted 8y ago[deleted]
- archgoon 8y agoMaking unsafe languages safe is not a design goal of WebAssembly. The author seems to believe that WebAssembly should provide many things that are the responsibility of the operating system and standard c library. I do not believe that is a good way of thinking about webassembly. It shouldn't be thought of as an operating system target (like Windows, Linux, or Mac); it should be thought of as an architecture target (like Arm vs x86). What the author wants is an operating system and runtime, which you can write for (and standardize on) web assembly and then load your program into it.
- garmaine 8y agoMany people seem to think it is. I work on the area of secure software stacks and the #1 “helpful” suggestion I get is “why don’t you use WebAssembly?” As if that made a significant difference to the attack surface, at all.
- jchw 8y agoWell, it certainly could be helpful, if part of your stack wants to run inherently untrusted code. I think this is what gets people excited by the idea of putting it into the kernel. It is a bit surprising, though, that many people do not realize WebAssembly doesn't make C code safe against itself.
- coder543 8y agoWebAssembly is designed to provide safety, in the sense that WebAssembly programs are sandboxed and unable to do anything you don't give them permission to do. WebAssembly won't make the runtime behavior of your programs correct, which is what the article seems to be getting at, but that doesn't make the WebAssembly VM model unsafe or insecure from a host perspective. If you isolate untrusted code in a WebAssembly VM, that should reduce the attack surface for the system as a whole to whatever functions you expose into the WebAssembly VM. Personally, my bias is to suggest that using Rust would significantly cut down on (but not eliminate) the attack surface inside the WebAssembly program... but some people don't like to hear that.
- 8y ago
- nickcw 8y agoI'm not sure the NULL pointer access being allowed point is valid. The C standard allows for the NULL pointer to be numerically any value, not just 0, and on some architectures in isn't 0. So I would hope C compilers targeting wasm would just use a different value for the NULL pointer, eg 0x8000000000000000 not 0. Whether they actually do or not I don't know, but it isn't an architectural failing of wasm.
- deleted 8y ago[deleted]
- hpbd 8y agoYou are right, but changing the starting address of the WebAssembly memory map to something else (like 0x8000) would've been easier.
- kllrnohj 8y agoYou can have a valid pointer to 0x00, but you only see it on microcontrollers and it doesn't really exist in any context WASM is being discussed. The author's argument that this is a mistake is true. WASM should almost certainly have had some arbitrary offset like 0x1000 just due to the extreme commonality of null pointer derefs, and changing NULL to something else won't come close to solving that problem. You still have pointer derefs of fields in structs that were calloc'd or memset(0)'d. Compiler can't magically swap out the writes-to-zero there with whatever NULL should be instead.
- saurik 8y agoInstead of providing some one-off special case for addresses close to 0, they could have what actual computers actually have: a way to mark regions of memory as unusable (which the WebAssembly code could then do), which would also provide help with other issues like stack overflows.
- kllrnohj 8y agoWhat computers actually have is literally just an arbitrary offset to catch null pointers. They then also have ways to mark pages as read-only and such, but they don't burn a bunch of pages on this for NULL pointer catching. They simply just don't map anything before the program offset.
- pcwalton 8y agoThe general point that this article makes is true--C and C++ are still unsafe, even if you execute them in a VM--but there are some very important caveats to note: * ROP should be impossible in Web Assembly, because the call stack is a separate stack, inaccessible from the heap and effectively invisible to the program. * For the same reason, classic buffer overflow attacks involving attacker-supplied machine code are impossible. In addition, Web Assembly bytecode is never mapped into the heap, so attackers cannot inject shellcode via the usual methods. * Mmap functionality is proposed for the future [1], which would allow for the implementation of guard pages. (Guard pages are fairly weak defenses anyway...) I'm sure that it's possible to attack a Web Assembly program's control flow by overwriting vtables and function pointers and taking advantage of the resulting type confusion. But it's significantly more difficult than it is in native code. [1]: https://github.com/WebAssembly/design/blob/master/FutureFeatures.md https://github.com/WebAssembly/design/blob/master/FutureFeat...
- pjmlp 8y agoIf WebAssembly had tagged pointers that could be avoided, as proven by Solaris for SPARC with ADI in production. Because when something is possible in security attacks, it will eventually be exploited.
- pcwalton 8y agoADI doesn't seem to me to have enough bits to effectively protect against vtable type confusion. Besides, nothing stops a wasm compiler from emitting such checks itself, if it wants to.
- ncmncm 8y agoIt is worse than the title says: a key tool for trapping corrupted process state, null pointer segfault, is turned off in WebAssembly targets. The second most common source of process corruption, integer overflow, usually ignored in native targets because direct memory corruption is so much worse, is also adopted into WebAssembly wholesale. This is all overwhelmingly worse than in the native case, because we make some effort to run only trustworthy native code, but browsers actively solicit unknown code from known-hostile sources--most particularly, web ads. The existence of safe-ish languages doesn't help, because there is no incentive to deploy them in user-hostile code fragments.
- AgentME 8y ago>This is all overwhelmingly worse than in the native case, because we make some effort to run only trustworthy native code, but browsers actively solicit unknown code from known-hostile sources--most particularly, web ads. The existence of safe-ish languages doesn't help, because there is no incentive to deploy them in user-hostile code fragments. WebAssembly strongly sandboxes WASM modules that are executed, so the situation where an attacker creates and serves a malicious WASM module to the user's browser is one that is handled well. The article is saying that WASM's protections stop a module from escaping its sandbox, but it doesn't prevent a buggy module from having its own memory get corrupted by its own memory-related bugs common in unsafe languages.
- indolering 8y agoWASM was designed to be fast enough to compete with native code and can't do integer overflow checking without serious performance regressions - Rust had to make the same tradeoff. Furthermore, induction and compiler optimizations can remove the need for such checks. Aren't you solving this at the wrong layer of abstraction?
- azakai 8y ago> there would be clear benefits in also delegating basic dynamic memory management to the host. It would be quite hard to spec malloc/free into the Web platform, because of the necessary detail: the behavior of that malloc/free pair would need to be identical (same pointers returned from malloc) in all browsers, for every possible sequence of allocations and deallocations. GC is actually easier to spec since so much of the underlying details are unobservable. It's not impossible in theory, but it seems like it would mandate all browsers use the exact same allocator implementation (say, dlmalloc version x.y.z). In addition, this would not allow optimization over time, again, unlike GC. In the non-browser case, server-side implementations may not need to worry about specs, so more options may be open there.
- pedrocr 8y ago>the behavior of that malloc/free pair would need to be identical (same pointers returned from malloc) in all browsers, for every possible sequence of allocations and deallocations Why would you ever spec it like that? That doesn't seem needed at all. Plenty of programs run across platforms with wildly different mallocs and everything runs file. Replacing the malloc with LD_PRELOAD tricks is even done sometimes.
- azakai 8y agoFor almost all platforms that's true, but the culture of standardization on the Web is unique. It comes from wanting a Web page to have the maximal chance of running across all standard-compliant browsers, forever - that's just not the case for practically every other platform.
- pedrocr 8y agoIf only that was true. Javascript has had all plenty of inconsistent behaviors across browsers and the feature matrix for what is and isn't supported in each browser is hugely complex. And even if that was true standardizing the results of malloc makes no sense, it gives you no extra compatibility guarantees for any sane programs and no one cares about insane ones.
- devit 8y agoNULL pointing to valid memory seems like a serious flaw that can and should be easily fixed.
- DannyBee 8y agoThere have been plenty of real environments where NULL pointed to valid memory (AIX, for example) It also has a reasonable use case ( or did, pre Spectre). It allows you to hoist and speculate loads that may be null. Since it is valid memory, instead of a fault, you would just get a result (usually zero on most of these platforms) you would throw away if it was not needed.
- kbumsik 8y ago> First, hosts have no visibility on how memory is being managed within a guest. Want to diagnose memory leaks? Good luck with that. Is that really true? I think we can implement a memory allocator done by hosts. By using "import" feature of WASM, a guest could implement a memory allocator that imports functions from the host that ask the host to look through the gest's memory directly (it is possible in JS code) and then allocate one. Maybe it will be slower but it is certainly possible that hosts can know what is happening to the memory in this way.
- abecedarius 8y ago> Memory is represented as a single linear block iirc you can have multiple instances or modules, each with its own private linear memory, and they can be set up to call each other's exported functions. It's just that current compilers don't use that encapsulation when compiling a single program. Am I wrong about this? (I haven't used WebAssembly, only read about it some time ago. But here's a link in support: https://groups.google.com/forum/#!topic/e-lang/3A6zYWF6u5E https://groups.google.com/forum/#!topic/e-lang/3A6zYWF6u5E "Multiple module instances only share an address space if they explicitly export/import a linear memory, which is just another kind of module-level definition. A module can define its own linear memory and not export it, in which case nobody else can access it.")
- kbumsik 8y agoIt might be possible when exchanging only numbers. But I think it's going to be quite tricky when exchanging pointers of buffers between modules since values of a pointer in a module is meaningless to the other module if the momory block is not shared.
- pier25 8y agoI love the idea of WebAssembly in the browser, but what's the point of using it as an universal module language everywhere else? We can already run most popular languages pretty much anywhere, and I imagine at better performance than WebAssembly, no?
- josephg 8y agoThe advantage is that code run through WASM is fast, sandboxed and platform-independant. Nothing else is capable of giving you all 3 of those features. Embedded scripting languages (JS / Lua) are platform-independant and sandboxed, but much slower than native code. C is fast and small. It can be very carefully sandboxed by the OS (eg iOS apps) but the sandbox has historically been very leaky. Also binaries must target a specific hardware architecture. The JVM & .NET environments are platform independent, but their heavy reliance on garbage collection slow them down. They also both have large runtime environments which makes them more awkward to embed. I wouldn't want to embed the JRE inside the linux kernel or in a web browser because its so big and it has such a terrible security track record. But WASM would work great. What other technology would be a good fit for making mods for a multiplayer game? Java? Too bloated. Lua? Workable but slow. C? You can't ship 3rd party mods safely and even if you could they would need to be recompiled for every platform. But WASM will work great. What other tech could you use to run a user-supplied filesystem driver in-kernel? Everything else is too slow (lua) or too unsafe (C).
- deleted 8y ago[deleted]
- pier25 8y agoOk, plugins/mods for real time applications are a good use case. Not only games, but also databases, web servers, etc. I'm starting to see the value in using WebAssembly outside the browser.
- danShumway 8y ago> Technically, this can be implemented already. However, for successful adoption, a standard interface has to be defined. This is literally the opposite of how the web works. The web is based on the Extensible Web Manifesto[0], where first we come to a consensus and see widespread adoption, and then we make a standard that reflects that consensus. > We have a fantastic and highly secure execution environment from a host perspective. But from the guest perspective, that very same environment looks like MS-DOS, where memory is a giant playground with no rules. Well, yeah. Add me to the list of people who are just kind of confused about why fixing C's problems is the responsibility of the browser, and why people thought that it was ever a priority for WASM. WASM is a VM-like isolation chamber for low-level code. It's not designed to make your code safe, it's designed to protect the host environment from unsafe code. I've seen multiple people make the argument that manually laying out memory in WASM is a design flaw rather than one of the biggest points of the entire implementation. Manually laying out memory with close to zero restrictions or paradigms or safeguards is the thing that makes WASM good. I feel like I missed something, I don't know where people got this idea that WASM was trying to be a higher level tool. It's an extremely low-level language-agnostic compile target for both safe and unsafe languages, and languages that care about safety should add their own safeguards as they see fit. [0]: https://github.com/extensibleweb/manifesto https://github.com/extensibleweb/manifesto
- jillesvangurp 8y agoC is unsafe because it comes with no memory protections. In an environment like a typical operating system (depending on the OS of course), there's a chance it will escape its sandbox. This risk does not exist in wasm. You can write the most atrociously misguided C ever and run it in wasm and know for sure that it will never do anything worse than corrupt its own program state. You get similar benefits by using a decent OS and/or by putting the untrustworthy code in e.g. a docker container. It's still code that can't be trusted but at least you are setting some hard boundaries that have no easy/known ways of being bypassed. However, it would still be bad if the program gets compromised. If, say, you are handling some credit card details and are using some C code to do that and it gets compromised, all of the interesting stuff (i.e. the credit card details) would be inside those boundaries. This is why using C to do that is not a great idea. This is a concept that is often misunderstood by people: most of the interesting stuff (from a hacker point of view) happens inside the sandbox. This is where you access and handle sensitive data and access protected resources (e.g. a third party website). Many attacks use relatively low tech mechanisms such as script injection, man in the middle attacks, social engineering, etc. Wasm indeed does nothing to protect against that. If you are handling user input in any way, that is potentially a way for hackers to inject code in your sandbox. If that sandbox has access to or control over anything interesting, that just got compromised. If you are using a language that is notorious for its decades long history of input validation mechanisms getting compromised (cough C cough), that means you can't trust input validation to function properly even inside a wasm container. This is exactly how many browser attacks work. They don't install viruses on your machine or whatever but they simply trick you into revealing your credentials, visiting some evil website, or entering your credit card. A bit of injected javascript or a redirect is all that this takes. Any injected code never leaves the sandbox; it doesn't have to.
- pjmlp 8y agoWhich is exactly why C++ modules in the CLR are marked as unsafe. There used to be the possibility to restrict the C++ language to a safe subset via /clr:pure and clr:safe switches, but now Microsoft official position is that C# or other .NET languages, are the only way to effectively write safe and verifiable code. https://docs.microsoft.com/en-us/cpp/build/reference/clr-restrictions?view=vs-2017 https://docs.microsoft.com/en-us/cpp/build/reference/clr-res... https://docs.microsoft.com/en-us/cpp/dotnet/pure-and-verifiable-code-cpp-cli?view=vs-2017 https://docs.microsoft.com/en-us/cpp/dotnet/pure-and-verifia...
- kiriakasis 8y agoThere is a yet in the original title.
- kiriakasis 8y ago> While escaping the sandbox itself may be difficult to achieve, application security doesn’t benefit from the mitigations commonly found in traditional environments. I feel this the most important point regarding use server-side.
- cyberbullets 8y agoThere is also another blog post (link to white paper inside) that talks about different memory safety issues with WebAssembly if using a memory-unsafe language: https://www.forcepoint.com/blog/security-labs/new-whitepaper-memory-safety-old-vulnerabilities-become-new-webassembly https://www.forcepoint.com/blog/security-labs/new-whitepaper...