I was looking at WASM in the Rust standard library again and spotted an implementation of the TcpListener::accept
method.
Now, why is this interesting? I’ll try to explain as best I can: Most Rust applications use the standard library which is an abstraction over system libraries that do various things like networking and file system access. Such applications should work on most major operating systems. The Rust standard library takes care of calling the system-specific APIs. The TcpListener::accept
method will differ between Windows and Linux. But, WASM is a little different from Windows and Linux.
WASM is a kind of virtual computer processor, like an Intel or AMD processor. In itself, this processor is a primitive component that does very low-level things. Adding up numbers, transfer data in memory and communicating with other components through buses. This is were operating systems like Linux and Windows come in; they implement all kinds of drivers so the processor can communicate with other components. And this is what Rust’s standard library ultimately relies on. So, how does WASM communicate with the network or file system?
WASM is different from your real processor because it is virtual. This means it actually has a ‘host’ that runs it. That means that if WASM were to want to access the network, it always has to go through the host. And this is exactly what WASI defines. It’s the system interface, similar to how Windows and Linux have interfaces for us to talk to the network or file system. So, just like you can use Linux to access the network, you can use WASI to access the network. But, WASI will ultimately rely on the host to provide it. The way this should work is that the host decides what access the program gets.
A very interesting talk I can recommend is this one:
The author explains the current way UNIX works and an improved way of thinking about capabilities (for networking sockets and files). By now, his implementations have been deprecated, and he refers to WebAssembly as a possible alternative. WebAssembly now builds on the ideas of the author.
Back to the TcpListener::accept
example. As far as I understand: If you write a Rust application with a TcpListener
and compile it to WASM-WASI, this program can be run with wasmtime
. The accept
call only accepts an already existing socket, so that means that the socket already has to be open. This is what wasmtime
can do for you. You can tell it to open a socket, then run your program so that the program can accept incoming connections on that pre-existing socket.
This means the program is capability-based. It can only open sockets you provide it with. Files work similarly, the program will only open files you open for it. So, the program can’t open random files to read from and this is what it is all about: limiting the capabilities of a program to make sure it can’t do anything else than what it needs. This is for security purposes, so that if the program is hijacked by an attacker, it can’t do much harm. It can’t read from random important files etc.
There is a tracking issue that made this all possible here. Due respect for the people working on this!