back
118 comments
Sounds like the big idea from Singularity (run everything in the same hardware security ring, use static analysis for memory safety) is going mainstream, incrementally. Unfortunate that this is happening right as it becomes clear that such a design is fundamentally unsound on modern hardware.
+1 for pointing at the irony but it's not really true.

1. Hardware design flaws are not irremediable and will be fixed in time.

2. It's still very useful to run software that is trusted to not be malicious and/but not trusted to be void of memory bugs.

> Hardware design flaws are not irremediable and will be fixed in time.

There's no particular reason to believe this. Neither Intel nor AMD have committed to any form of side-effect-free speculative execution or similar. That'd required a rather large chunk of transistors and die space, and if nobody is footing the bill for it it's not going to happen.

Preventing side-effects from leaking between processes (and ring levels) entirely at the hardware level is definitely going to happen. Within a process, though? That's not going to happen without multiple major players demanding it. Since nearly all the major CPU consumers are currently happy with process boundaries being the security enforcement zones, there's no particular reason to believe that in-process sandboxing will ever have hardware fixes to prevent spectre attacks.

Wasmjit doesn't really address #2. Memory bugs in nginx will continue to corrupt data and potentially allow RCE, they just will not be allowed to spread to the rest of the kernel (in theory)
Not without a big performance hit most servers don't need because they don't cross security domains.
The big news this year was that the majority of hardware isolation designs in existence were fundamentally unsound, this is a software sandbox. Are you referring to the recent discovery of a new hardware bug class here?
As I understand it, there were basically two bug classes. One was that code that makes faulty fetches across a hardware privilege boundary can infer data from how long the fault takes. Another was that characteristics of branch prediction within the same process can reveal information about the branch path not taken, even if that branch is itself a bounds check or other security check.

The first attack isn't relevant to designs that don't use hardware isolation, but the second one absolutely is. If your virtual bytecode (wasm, JVM, Lua, whatever) is allowed access to a portion of memory, and inside the same hardware address space is other memory it shouldn't read (e.g., because there are two software-isolated processes in the same hardware address space), and a supervisor or JIT is guarding its memory accesses with branches, the second attack will let the software-isolated process execute cache timing attacks against the data on the wrong side of the branch.

(I believe the names are more-or-less that Meltdown is the first bug class and Spectre is the second, but the Spectre versions are rather different in characteristics - in particular I believe that Spectre v1 affects software-isolation-only systems and Spectre v2 less so. But the names confuse me.)

The big news this year was that you can't run code of different trust levels in the same address space.
So is the idea to take a page from the RISC and VLSI playbooks and outsource the isolation and security to the compiler/JIT VM?
Not only Singularity.

Xerox Parc workstations, IBM and Unisys mainframes, UCSD Pascal, Oberon, Inferno, Java, .NET, Flash.

Or for more actual examples, Garmin Apps, watchOS bitcode, DEX on Android.

Java applets, Flash, and Silverlight were famously examples of people being overconfident in software isolation. There's been an active effort to kill off browser plugins, and wasm (and asm.js and Native Client before it) is the result of an attempt to accomplish the same goal in an actually sound manner.

Dalvik on Android is not a software isolation mechanism. Each app has its own Dalvik VM using traditional UNIX processes and user accounts for isolation, which are in turn powered by hardware isolation. (I'm betting they did this because they knew that JVM software isolation had been a disaster in practice, although in part this also means apps can link native code libraries without changing the security model at all.)

Inferno is close, but most of the others are really using a VM for portability and flexibility, not running code at ring 0.
What IBM systems are you thinking of?

System/360 had (and used) hardware privilege levels.

Seems like few of your examples involve not using hardware for process isolation. Java: no, except a few research OSes. Flash: no.

There is another layer of abstraction that is heavily being exploited of running layers of kernels. I'm really interested in seeing more advances in this and unikernal approach where if you are running in the cloud, the hypervisor already provides you with a sandbox, so run things at a lower level than necessary. There are certain secuirty challenges that we see because we keep thinking in terms of user and kernal space. If we try to narrow (and slowly remove) the line separating the spaces, we can address these problems in more efficient way than done today for sure.
gVisor is pretty interesting, it kinda takes this idea when you run it on KVM.

https://github.com/google/gvisor

Except minus the static analysis, right?
WASM gets statically verified before it runs.
The intention here is to use wasm to allow you safely run user code _within_ the kernel. Their primary targets are nginx and FUSE. Conceivably, avoiding the context switch into and out of the kernel will have significant performance implications, but there aren't any numbers out yet for nginx specifically.
That's certainly a fascinating idea. My initial thought was "Wait, doesn't the kernel already provide a sandboxed execution environment -- called userspace?" This would still have scheduling overhead, but I assume the idea is to avoid a lot of the other context switching steps such as switching page tables. And instead rely on Wasm/JIT checks to ensure ahead of time that memory violations won't happen.
Once upon a time syscalls were slow, but architectures now provide features like syscall/sysenter for switching privilege levels, with costs comparable to userspace function calls.

Once upon a time switching page tables was slow, but now we have features like PCID that allow preserving buffers.

Soon, if not already, the principle cost to context switching will be the necessity to flush prediction and data buffers. In-kernel solutions like Wasmjit must incur the same costs. Quite possibly they may turn out to be slower overall: 1) they won't be able to take advantage of the same hardware optimized privilege management facilities (existing and future ones--imagine tagged prediction buffers much like PCID), and 2) they still incur the extra runtime overhead of running in a VM which, JIT-optimized or not, eats into limited resources like those prediction and data buffers that have become so critical to maximizing performance.

Granted, if it's going to work well at all than Nginx seems like a good bet, especially because of I/O. But there are many other solutions to that problem. Obsession with DPDK may be waning, but zero-copy AIO is still a thing and there are more ergonomic userspace alternatives (existing and in the pipeline) that let you leverage the in-kernel network stack without having to incur copying costs. And then there are solutions like QUIC that redefine the problem and which should work extremely well with existing zero-copy interfaces.

CPUs are incredibly complex precisely because so much of the security heavy-lifting once performed in the OS is being accomplished in the CPU or dedicated controllers. And these newer optimizations were designed to be integrated within the context of the traditional userspace/kernel split.

Wasmjit looks like an extremely cool project and I don't doubt its utility. There's plenty of room for alternative approaches, I just don't think the value-add is all that obvious.[1] Probably less to do with performance and more to do with providing a clear, stable, well-supported environment for solving (and subsequently maintaining!) difficult integration problems.

[1] I just want to reiterate that by saying the value-add isn't obvious I'm not implying anything about the potential magnitude of that value-add. I've been around long enough to understand that most pain points are invisible and just because I can't see them or people can't articulate them doesn't mean they don't exist or that the potential for serious disruption isn't there.

Last time I measured this, the time it took the Linux scheduler to decide what task to schedule was far more than the time it took the entry code and CPU to switch from user to kernel or vice verse. Meltdown changes this, but Meltdown-proof AMD CPUs are all over and Meltdown-proof Intel CPUs should show up eventually.

So I don’t see the point.

One step closer to METAL[1]

[1]: https://www.destroyallsoftware.com/talks/the-birth-and-death... (at 18:46)

Use Sendfile and if that's not enough try netmap or ddpk, why would I want to run Nginx in kernel space?
I don’t understand. How is this possible? The POSIX API is not implemented for WASM. Non web embedding have not yet been standardized, nor threads. How have they implemented this? Are they implementing a non standard embedding and pthreads?

https://webassembly.org/docs/non-web/

It seems like wasm will finally enable the "write once, run everywhere" promise that java made but never truly executed by starting with the premise that you don't need "one true language" (java), but rather just the VM.

Yeah, I know the JVM supports several languages these days but most require non-superficial similarities to Java (garbage collected, etc.)

This ignores the tons and tons and tons of work that would really have changed that. I don't think it really has anything to do with whether you have one true language or not.

There were plenty of well-funded efforts to have "write once, run everywhere" in the past that were just VM's and formats (ANDF, etc).

In practice, a lot of things have changed since Java that have made this kind of approach feasible. As a simple example: good compiler infrastructure to build on top of is much more available than it was then. These days you pretty much just have to write a frontend.

Even though GCC existed then, it was still compiling statement at a time!

You literally can't write a portable "hello world" command line app in WASM. It's the worst "write once, run everywhere" of anything. Which is expected because it distinctly does not provide any standard APIs or syscalls. There's no standard library. At all.

Someone may attempt to add a batteries-include system that uses WASM with a bunch of platform-abstraction libraries, but WASM itself does not provide that. And isn't going to provide it.

You can make a portable library with WASM, assuming you have zero dependencies on anything, but that's about it.

> but most require non-superficial similarities to Java (garbage collected, etc.)

It should be noted that doing this requires non-superficial similarities to *nix/POSIX (signals, files, threads, etc). It's not like you could run Nginx on this without its POSIX impl or in the browser w/out Emscripten's POSIX impl or on any other WASM runtime w/out a POSIX impl.

> most require non-superficial similarities to Java (garbage collected, etc.)

You can (obviously) implement any language without garbage collection semantics using garbage collection, so this requirement is false.

See for example languages like C and C++ running on the JVM.

How do you avoid having to copy buffers from the kernel into WebAssembly? As far as I know WebAssembly does not provide a way to access memory outside the linear memory block, but maybe in this specific case (nginx) it is possible to have all syscalls write to a buffer allocated by WebAssembly.
Wasmer just got nginx working on their wasm runtime as well!
I might be getting too old, because I truly don't get the benefit of doing this... Nobody I know really cares about portability, and I don't see how running nginx with WASM is in any way better than running it directly on the system. Does anyone care to ELI5 for me?
This is satire but still very interesting: https://www.destroyallsoftware.com/talks/the-birth-and-death...
Running it in the kernel removes the overhead of context switching into the kernel for I/O (and other things), so it could be faster. Although as this post says, right now it's only running in user space.
Does anyone else look at this title and see a jumble of letters?

I miss the days of pronounceable acronyms

"engine-ecks on whaz'm-jit" It's certainly pronounceable, though perhaps that pronunciation is non-obvious.
At a glance it actually looked like Dutch to me (with apologies to my Dutch buddies!)
Obligatory birth-and-death-of-javascript

https://www.destroyallsoftware.com/talks/the-birth-and-death...

I suppose calling it METAL would have been too on-the-nose.

Not sure why you're downvoted, this is a very interesting talk.
Hi HN!

I'm Syrus, from the Wasmer team. We have been working in something similar, but with a special focus on maintainability and with bigger goals in mind:

https://wasmer.io/

Here is the article about our journey on Running Nginx (which funnily enough we actually accomplished just before wasmjit):

https://medium.com/@syrusakbary/running-nginx-with-webassemb...

> but much more maintainable.

> we actually accomplished just before wasmjit

> Wasmer is the first native WebAssembly runtime [...]

Whoa there. I like both projects and respect competition as much as the next guy, but maintainability is subjective and being first is of little importance.

Can you run Wasmer in the Linux kernel? What makes Wasmjit stand out from all other WebAssembly virtual machines (WAVM, Wasmer, Life, wasmi, wagon, ...) is that its main goal is to run WebAssembly in kernel space.
I was looking into something like this in order to port a POSIX-only program to run on Windows.

Does anyone know how to link in native OpenGL system libraries? I'm looking to link to native graphics libraries so that I don't have to pass through Emscripten's OpenGL -> WebGL emulation layer. I'd like to drop the browser render layer all together and just have GLFW or SDL take care of rendering native client windows.

I was looking into (ab)using wasmer for compilig dylibs to wasm and load them with Python. Do you know if someone already tried something similar?
How are you different from wasmtime?