Skip to content

Comment on The Risks of WebAssembly

Comments

What does one benefit from compiling and running microservices in WASM as opposed to running it in say Rust?

- Strong isolation constructs. With WebAssembly, there's no access to the host system by default. Even something as simple as reading the system clock requires exposing the appropriate WASI API to the WASM module.

- The ability to snapshot and later restore running state.

- A cross-platform and language-agnostic way to distribute plugins (e.g. Envoy proxy allows loading WebAssembly modules as extensions)

A snapshot a running state of a bytecode based execution engine, where did I heard that before,

https://en.wikipedia.org/wiki/Jini

https://dl.acm.org/doi/10.5555/867785

You can now build Jini and agent systems on top of the web!

With WASM you get the sandbox for free. This makes it safer for the service to provide arbitrary file uploads that get run on their platform without adding the overhead of virtualisation or containerisation.

Another thing WASM adds is cross language calling capabilities, i.e. calling Rust code from Go in a standard way. All methods are hidden behind a severely limited runtime interface so all have to comply with the respective standards.

This all comes at the cost of performance and efficiency just like on the regular "cloud".

Individually, you'll have a much easier time running your payload on bare metal, especially if you write code in a language that doesn't already compile to bytecode or gets interpreted and JIT'ed.

In a multi tenant system, the free sandbox means you'll have rather little work to safely run arbitrary payloads. If they can get enough customers, they'll be able to provide services cheaper by leveraging their economy of scale and low cost security mechanisms.

Is included sandboxing really that useful? Why not use a standalone sandbox, or OS’s permission system, MAC, etc? Especially that the biggest problem is the program corrupting itself, which will readily happen if we make C and friends more popular again for these kinds of applications.

There's an important difference in effectiveness when it comes to blacklisting APIs that were designed to be open rather than whitelisting APIs from within a closed system. There are tons of sandbox escapes that get discovered and patched each year, usually because of race conditions or the complex systems that the container APIs and general system APIs use to protect against each other. This is the reason why symlinks require administrator permissions in Windows, for example: the security model around symlinks is very complex and there have been tons of privilege escalation/arbitrary file read/write exploits just around something as conceptually simple as a symlink. Microsoft chose to restrict them to privileged users because they consider them to be too difficult to properly defend against.

A WASM executable can do nothing but allocate memory and change the contents of such memory. There's no I/O, no socket state machines, no kernel communication, it's all just numbers in, numbers out. Even something "simple" like entering a string into a WASM program involves treating that string as arbitrary memory to be operated on by the WASM runtime and things like structs, pointers and classes must go through several layers of abstraction before they can be used.

From this numbers-in-numbers-out mechanism further standards are currently evolving, standards that allow exposing callbacks and other such APIs into the WASM code. There's still an abstraction layer between the two, but the runtime can now allow the code to do a bit more.

I'm not too fond of the way these APIs are turning WASM into "Java but Javascript" but it's still good to see the security first approach to WASM runtimes that won't allow the code to do anything they don't provide rather than to allow everything except for a subset of functionality. The default model of modern operating systems is "you have all permissions, except these" rather than "you have these permissions and may ask for more". Trying to use seccomp and syscall filtering in Linux is a terrible experience because it's hard to know for sure that you've set up every possible limit you can in order to neuter exploits.

To see the benefit of this approach, look at the sandboxing in mobile operating systems like Android. Earlier permissions weren't a good fit for application developers and over time they've evolved. Google has had to patch in more and more limitations to prevent malicious behaviour like tracking (except for their own tracking, because Google). They've lifted some restrictions, like the INTERNET permission being granted by default in practice, but most of their API changes have been centered around taking away application functionality and providing a more restricted alternative.

Now, I very much like the option to root my phone and do whatever the hell I want on it, but I don't want the random crap the local weather app's advertisers try to force down my throat to have too much of an impact on my phone.

Personally, I tend to install PWA versions of web apps rather than download stuff from the Play Store if I can because I don't want these websites to have that much access to my phone (and often they're just wrappers around websites anyway).

With WASM, C's problematic memory management isn't as much of a problem. Your program can crash, show weird text, do anything weird you can think of, but it can't jump to kernel mode or escape the sandbox without a very significant flaw in the runtime whitelisting code. Redirect the control flow of a WASM program that can only serve web pages and control the files in two specific paths and you're practically nowhere. You can probably read some files but there isn't even a guarantee that you can upload the contents of the database anywhere, because networking is opt-in!

For most people in most cases I would very much prefer to keep running on bare metal myself. Safe programming languages are great and much more capable of being optimized because WASM itself is two compatibility hacks stacked on top of a Javascript library; it'll take a while for the format to be competitive and even then it won't compete with Rust in terms of performance.

However, the inexplicable urge to move to vendor lock-in through stuff like Amazon Lambda and the mistaken idea that every application needs the complexity of Kubernetes for some reason are undeniable. Within these contexts, I can see the benefits of what WASM people are trying to achieve.

Thanks for the detailed explanation. Under OS security model I meant mostly more modern approaches like Android (especially GrapheneOS) or iOS — desktop OSs have plenty of catching up to do here.

Android for example runs everything as a separate user with very restricted abilities, and require IPC for any “elevated permission” operations, which are checked by a separate daemon process before being allowed on its behalf.

And I think heap corruptions should not be taken lightly - I was thinking that you mostly mean server processes before, as in these cases a memory corruption can lead to exposing other user’s data, which is a huge step back from the predominantly used Java/C#/etc backends. The concept of well-defined failure is very important and for example a Java program will never get into such an undecidable state an “unsafe” language can.

you don’t run a service in rust, you compile, distribute, and run machine code on your cpu. compare to wasm where you compile to portable ISA and the runtime recompiles to real ISA. the wasm virtual environment is a gazillions of times simpler than a hardware context with all the attendant complexities.

Yes, abstractions are simpler, but they are also slower. It depends what you need.

(personally I am going to invest heavily in wasm)

One gets to re-invent 20 years of JVM and CLR, even more if counting mainframe/micro language environments, and sell the company to VC as mondern cloud.

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.