WASI资料
本文不含原创,只是知识的搬运工。
1. WASI 是什么?
WASI是WebAssembly System Interface的缩写。WebAssembly,我们都知道,是一种新的字节码格式,目前被应用于 web 中,由于其可移植、体积小、安全性的等优点被渐渐广泛认可,但是其主要是运行在浏览器中。
一些天才们,想让 WebAssembly 也可以运行在非浏览器环境中,这就产生了 WASI。
因此,这样会有一些问题需要解决。我们知道,一些语言,比如Rust,都有自己的标准库,标准库对系统调用进行了封装,让我们写的代码可以跨平台,这实际上是源代码的可移植性。
wasi 这里需要可移植的是二进制文件(.wasm)和一个跨平台的 runtime,也就是说,我们在某一个平台上生成了.wasm,直接拿到其他平台上,也可以直接使用。
我们在设计这个 runtime 的时候,有两个关键点需要考虑:
- 可移植性(上文提到的,二进制级别的可移植性)+ 可扩展性
- 安全性
关于安全性
传统的软件开发,是以用户级别来进行权限管理的,也就是说,这个用户有什么权限,以这个用户的名义运行的程序就有什么权限,这样就可以避免不同用户之间互相影响。这样无疑是科学的,但是现在的问题是:现今大多数情况,我们的电脑只有一个用户,但是运行的程序可能来自各处,而程序本身可能是不安全的,所以像以前那样以用户级别来进行权限控制,其实是不安全的。
所以wasm提供了一种更细粒度的权限控制。因为wasm有二进制模块和一个运行时,所以我们做这样几个工作:
- 先定义一套标准的系统调用接口:
wasi-core
- 各个平台(windows、unix)对标准接口进行平台实现
- 对于一个具体的 wasm 程序,需要把其允许调用的接口在运行的时候传入,比如对于一个 wasm 模块,我只传入
__wasi_path_open
这样一个接口,因此 wasm 中就只能用这样一个接口(使用过 web 端的 wasm 同学,是不是对此十分熟悉) - 同样的,对于文件路径也是,只允许对传入的文件路径进行操作,例如只传入
/tmp
路径,wasm 模块就没有办法对/User
路径下的文件进行操作
这样的设计更细粒度地保证了安全,同时也具备了可移植性。
与此同时,除了上文提到的wasi-core
系统接口,我们还可以定义wasi-xx
模块接口,然后运行时传入,这样也具备了可扩展性。
以上就是 wasi 的一些基本介绍,目前其有三个实现,可以尝试:
- wasmtime:Mozilla’s WebAssembly runtime
- Lucet:Fastly’s WebAssembly runtime
- a browser polyfill
2. Mozilla Announces WASI Initiative to Run Web Assembly on All Devices, Computers, Operating Systems
来源:https://www.infoq.com/news/2019/04/wasi-wasm-system-interface/
Mozilla recently announced a new standardization effort aiming at running the same WebAssembly code across all devices, machines and operating systems.
WASI是定义了标准化系统接口,使WebAssembly能跨设备、跨操作系统运行。
这个“recently”应该是指2019-03-27
,是Lin Clark发表文章宣布:
Today, we announce the start of a new standardization effort — WASI, the WebAssembly system interface.
The new standard, WebAssembly System Interface (WASI), defines one single conceptual operating system interface, which can be implemented by multiple, actual operating systems.
WASI定义了一个单一的概念性操作系统接口,可以被多个实际的操作系统实现。
At the difference of previous “Run Anywhere” efforts like Java, WASI builds on WebAssembly, a rare collaboration between browser vendors and manufacturers of chips, devices, computers and operating systems to produce a patent-free, open standard. The WASI standard will strive to provide WebAssembly’s portability and security through a modular set of standard interfaces, and to provide a solid foundation for an ecosystem. Mozilla and Fastly are already shipping prototypal WASI implementations.
WASI aims to be a system interface for the WebAssembly platform (currently implemented by the four major browser engines). WebAssembly (Wasm) describes itself as a “binary instruction format for a stack-based virtual machine”, with the design goal to “execute at native speed by taking advantage of common hardware capabilities available on a wide range of platforms”. Wasm is used as a target for compilation of high-level languages like C/C++/Rust. While WebAssembly was primarily designed to run on the open web, Mozilla seeks now to extend WebAssembly’s reach to non-web embeddings, “including everything from minimal shells for testing to full-blown application environments e.g. on servers in datacenters, on IoT devices, or mobile/desktop apps”. As Lin Clark observes:
Code outside of a browser needs a way to talk to the system — a system interface. And the WebAssembly platform doesn’t have that yet.
WASI’s stated goal echoes the original Java promise to “Write Once, Run Anywhere”. The Java Virtual Machine (JVM) indeed serves a similar purpose, and language flexibility similar to that offered by the WebAssembly platform may be realized in Java via the GraalVM. Java, however, remains a de facto standard, and its owner Oracle has a lawsuit pending against Google for allegedly using unlawfully Java’s APIs. By contrast, WebAssembly is the result of a rare collaboration between browser vendors and major companies such as Microsoft, Google, Apple, Mozilla, Intel, Samsung and more. Jay Phelps emphasized at QCon San Francisco 2018:
(…) these companies, they’ve come together and they’ve all created the first standardized byte code by all of these major companies. And it’s free. It’s not a proprietary program. There’s no question that this is completely open. And it’s not encumbered by patent laws and all that sorts of things.
Furthermore, Wasm, being memory safe and tuned for validation, may have security advantages over Java. Till Schneidereit provides extra arguments to the comparison in favor of Wasm:
(…) WebAssembly has been designed to scale from tiny devices to large server farms or CDNs; is much more language-agnostic than Java; and has a much smaller implementation footprint.
WASI seeks to achieve portable binaries by specifying a common interface to multiple systems, based on abstractions of system functionalities. Such abstractions are clustered into modules, with wasi-core occupying a central role. Lin Clark details:
wasi-core will contain the basics that all programs need. It will cover much of the same ground as POSIX, including things such as files, network connections, clocks, and random numbers.
Other functionalities, like multimedia, 3D graphics, or smart contracts, may be addressed by specific modules. The standardization effort in place aims at specifying carefully the system functionality abstractions to address a large set of operating systems and architectures, while maintaining the performance objective of WebAssembly.
WASI builds on the security aspect of Wasm by adopting a capability-based security model. WASI applications are provided with capabilities, instead of forgeable references (such as a file path) which identify a resource, but do not specify which access rights are appropriate for that resource. Forgeable references force validation by the operating system based on the ambient authority of the requesting program. Lin Clark explains how a WASI app can only open a file if it previously has been given the capability to open that file:
(…) you can’t have code that randomly asks to open /etc/passwd. Instead, the code can only operate on the directories that are passed in to it. (…) So the runtime passes in the file descriptors that an app can use to the top level code, and then file descriptors get propagated through the rest of the system on an as-needed basis.
WASI-enabled apps can currently be run in the browser with a polyfill, or outside the browser with Mozilla’s Wasmtime, or Fastly’s Lucet.
WASI is a work in progress. Lin Clark reflects:
But there are still questions we’ll need to address after wasi-core is fully standardized. Those questions include:
asynchronous I/O
file watching
file locking
The stakes are high. Solomon Hikes, co-founder of Docker, says:
If WASM+WASI existed in 2008, we wouldn’t have needed to created Docker. That’s how important it is. Webassembly on the server is the future of computing. A standardized system interface was the missing link. Let’s hope WASI is up to the task!
3. 原文解读
文档链接:Standardizing WASI: A system interface to run WebAssembly outside the web by Lin Clark on March 27, 2019
Today, we announce the start of a new standardization effort — WASI, the WebAssembly system interface.
Why: Developers are starting to push WebAssembly beyond the browser, because it provides a fast, scalable, secure way to run the same code across all machines.
But we don’t yet have a solid foundation to build upon. Code outside of a browser needs a way to talk to the system — a system interface. And the WebAssembly platform doesn’t have that yet.
由于WebAssembly的诸多好处(fast,scalable,secure,跨平台),产生了在浏览器外运行WebAssembly的诉求。但想要在浏览器外运行WebAssembly,就需要解决程序与操作系统之间通信的问题。(为了解决这个问题,WASI产生了。)
What: WebAssembly is an assembly language for a conceptual machine, not a physical one. This is why it can be run across a variety of different machine architectures.
Just as WebAssembly is an assembly language for a conceptual machine, WebAssembly needs a system interface for a conceptual operating system, not any single operating system. This way, it can be run across all different OSs.
This is what WASI is — a system interface for the WebAssembly platform.
We aim to create a system interface that will be a true companion to WebAssembly and last the test of time. This means upholding the key principles of WebAssembly — portability and security.
WASI是一个为WebAssembly平台设计的系统接口,为WebAssembly的可移植性和安全性提供支持。
Who: We are chartering a WebAssembly subgroup to focus on standardizing WASI. We’ve already gathered interested partners, and are looking for more to join.
Here are some of the reasons that we, our partners, and our supporters think this is important:
下面是一些有在浏览器外使用WebAssembly诉求的人对WASI的看法:
- Sean White, Chief R&D Officer of Mozilla
“WebAssembly is already transforming the way the web brings new kinds of compelling content to people and empowers developers and creators to do their best work on the web. Up to now that’s been through browsers, but with WASI we can deliver the benefits of WebAssembly and the web to more users, more places, on more devices, and as part of more experiences.”
由于WASI是要为WebAssembly提供非浏览器环境的支持,因此它可以把WebAssembly的优势推广到更多用户、更多设备。
- Tyler McMullen, CTO of Fastly
“We are taking WebAssembly beyond the browser, as a platform for fast, safe execution of code in our edge cloud. Despite the differences in environment between our edge and browsers, WASI means WebAssembly developers won’t have to port their code to each different platform.”
Fastly旨在将WebAssembly拓展到非浏览器环境,在edge cloud中提供一个快速安全地执行代码的平台。
- Myles Borins, Node Technical Steering committee director
“WebAssembly could solve one of the biggest problems in Node — how to get close-to-native speeds and reuse code written in other languages like C and C++ like you can with native modules, while still remaining portable and secure. Standardizing this system interface is the first step towards making that happen.”
有了WebAssembly,我们不但可以重用已经用C/C++写好的代码,还可以获得接近C/C++的运行速度。
- Laurie Voss, co-founder of npm
“npm is tremendously excited by the potential WebAssembly holds to expand the capabilities of the npm ecosystem while hugely simplifying the process of getting native code to run in server-side JavaScript applications. We look forward to the results of this process.”So that’s the big news! 🎉
There are currently 3 implementations of WASI:
- wasmtime:Mozilla’s WebAssembly runtime
- Lucet:Fastly’s WebAssembly runtime
- a browser polyfill
You can see WASI in action in this video: https://www.youtube.com/embed/ggtEJC0Jv8A
And if you want to learn more about our proposal for how this system interface should work, keep reading.
What’s a system interface?
Many people talk about languages like C giving you direct access to system resources. But that’s not quite true.
These languages don’t have direct access to do things like open or create files on most systems. Why not?
Because these system resources — such as files, memory, and network connections— are too important for stability and security.
If one program unintentionally messes up the resources of another, then it could crash the program. Even worse, if a program (or user) intentionally messes with the resources of another, it could steal sensitive data.
So we need a way to control which programs and users can access which resources. People figured this out pretty early on, and came up with a way to provide this control: protection ring security.
With protection ring security, the operating system basically puts a protective barrier around the system’s resources. This is the kernel. The kernel is the only thing that gets to do operations like creating a new file or opening a file or opening a network connection.
The user’s programs run outside of this kernel in something called user mode. If a program wants to do anything like open a file, it has to ask the kernel to open the file for it.
This is where the concept of the system call comes in. When a program needs to ask the kernel to do one of these things, it asks using a system call. This gives the kernel a chance to figure out which user is asking. Then it can see if that user has access to the file before opening it.
On most devices, this is the only way that your code can access the system’s resources — through system calls.
The operating system makes the system calls available. But if each operating system has its own system calls, wouldn’t you need a different version of the code for each operating system? Fortunately, you don’t.
How is this problem solved? Abstraction.
Most languages provide a standard library. While coding, the programmer doesn’t need to know what system they are targeting. They just use the interface.
Then, when compiling, your toolchain picks which implementation of the interface to use based on what system you’re targeting. This implementation uses functions from the operating system’s API, so it’s specific to the system.
This is where the system interface comes in. For example,
printf
being compiled for a Windows machine could use the Windows API to interact with the machine. If it’s being compiled for Mac or Linux, it will use POSIX instead.
This poses a problem for WebAssembly, though.
With WebAssembly, you don’t know what kind of operating system you’re targeting even when you’re compiling. So you can’t use any single OS’s system interface inside the WebAssembly implementation of the standard library.
I’ve talked before about how WebAssembly is an assembly language for a conceptual machine, not a real machine. In the same way, WebAssembly needs a system interface for a conceptual operating system, not a real operating system.
But there are already runtimes that can run WebAssembly outside the browser, even without having this system interface in place. How do they do it? Let’s take a look.
How is WebAssembly running outside the browser today?
The first tool for producing WebAssembly was Emscripten. It emulates a particular OS system interface, POSIX, on the web. This means that the programmer can use functions from the C standard library (libc).
To do this, Emscripten created its own implementation of libc. This implementation was split in two — part was compiled into the WebAssembly module, and the other part was implemented in JS glue code. This JS glue would then call into the browser, which would then talk to the OS.
Most of the early WebAssembly code was compiled with Emscripten. So when people started wanting to run WebAssembly without a browser, they started by making Emscripten-compiled code run.
So these runtimes needed to create their own implementations for all of these functions that were in the JS glue code.
There’s a problem here, though. The interface provided by this JS glue code wasn’t designed to be a standard, or even a public facing interface. That wasn’t the problem it was solving.
For example, for a function that would be called something like
read
in an API that was designed to be a public interface, the JS glue code instead uses_system3(which, varargs)
.
The first parameter,
which
, is an integer which is always the same as the number in the name (so 3 in this case).The second parameter,
varargs
, are the arguments to use. It’s calledvarargs
because you can have a variable number of them. But WebAssembly doesn’t provide a way to pass in a variable number of arguments to a function. So instead, the arguments are passed in via linear memory. This isn’t type safe, and it’s also slower than it would be if the arguments could be passed in using registers.That was fine for Emscripten running in the browser. But now runtimes are treating this as a de facto standard, implementing their own versions of the JS glue code. They are emulating an internal detail of an emulation layer of POSIX.
This means they are re-implementing choices (like passing arguments in as heap values) that made sense based on Emscripten’s constraints, even though these constraints don’t apply in their environments.
If we’re going to build a WebAssembly ecosystem that lasts for decades, we need solid foundations. This means our de facto standard can’t be an emulation of an emulation.
But what principles should we apply?
What principles does a WebAssembly system interface need to uphold?
There are two important principles that are baked into WebAssembly :
- portability
- security
We need to maintain these key principles as we move to outside-the-browser use cases.
As it is, POSIX and Unix’s Access Control approach to security don’t quite get us there. Let’s look at where they fall short.
Portability
POSIX provides source code portability. You can compile the same source code with different versions of libc to target different machines.
But WebAssembly needs to go one step beyond this. We need to be able to compile once and run across a whole bunch of different machines. We need portable binaries.
This kind of portability makes it much easier to distribute code to users.
For example, if Node’s native modules were written in WebAssembly, then users wouldn’t need to run node-gyp when they install apps with native modules, and developers wouldn’t need to configure and distribute dozens of binaries.
Security
When a line of code asks the operating system to do some input or output, the OS needs to determine if it is safe to do what the code asks.
Operating systems typically handle this with access control that is based on ownership and groups.
For example, the program might ask the OS to open a file. A user has a certain set of files that they have access to.
When the user starts the program, the program runs on behalf of that user. If the user has access to the file — either because they are the owner or because they are in a group with access — then the program has that same access, too.
This protects users from each other. That made a lot of sense when early operating systems were developed. Systems were often multi-user, and administrators controlled what software was installed. So the most prominent threat was other users taking a peek at your files.
That has changed. Systems now are usually single user, but they are running code that pulls in lots of other, third party code of unknown trustworthiness. Now the biggest threat is that the code that you yourself are running will turn against you.
For example, let’s say that the library you’re using in an application gets a new maintainer (as often happens in open source). That maintainer might have your interest at heart… or they might be one of the bad guys. And if they have access to do anything on your system — for example, open any of your files and send them over the network — then their code can do a lot of damage.
This is why using third-party libraries that can talk directly to the system can be dangerous.
WebAssembly’s way of doing security is different. WebAssembly is sandboxed.
This means that code can’t talk directly to the OS. But then how does it do anything with system resources? The host (which might be a browser, or might be a wasm runtime) puts functions in the sandbox that the code can use.
This means that the host can limit what a program can do on a program-by-program basis. It doesn’t just let the program act on behalf of the user, calling any system call with the user’s full permissions.
Just having a mechanism for sandboxing doesn’t make a system secure in and of itself — the host can still put all of the capabilities into the sandbox, in which case we’re no better off — but it at least gives hosts the option of creating a more secure system.
In any system interface we design, we need to uphold these two principles. Portability makes it easier to develop and distribute software, and providing the tools for hosts to secure themselves or their users is an absolute must.
What should this system interface look like?
Given those two key principles, what should the design of the WebAssembly system interface be?
That’s what we’ll figure out through the standardization process. We do have a proposal to start with, though:
- Create a modular set of standard interfaces
- Start with standardizing the most fundamental module, wasi-core
What will be in wasi-core?
wasi-core will contain the basics that all programs need. It will cover much of the same ground as POSIX, including things such as files, network connections, clocks, and random numbers.
And it will take a very similar approach to POSIX for many of these things. For example, it will use POSIX’s file-oriented approach, where you have system calls such as open, close, read, and write and everything else basically provides augmentations on top.
But wasi-core won’t cover everything that POSIX does. For example, the process concept does not map clearly onto WebAssembly. And beyond that, it doesn’t make sense to say that every WebAssembly engine needs to support process operations like
fork
. But we also want to make it possible to standardize fork.This is where the modular approach comes in. This way, we can get good standardization coverage while still allowing niche platforms to use only the parts of WASI that make sense for them.
Languages like Rust will use wasi-core directly in their standard libraries. For example, Rust’s
open
is implemented by calling__wasi_path_open
when it’s compiled to WebAssembly.For C and C++, we’ve created a wasi-sysroot that implements libc in terms of wasi-core functions.
We expect compilers like Clang to be ready to interface with the WASI API, and complete toolchains like the Rust compiler and Emscripten to use WASI as part of their system implementations
How does the user’s code call these WASI functions?
The runtime that is running the code passes the wasi-core functions in as imports.
This gives us portability, because each host can have their own implementation of wasi-core that is specifically written for their platform — from WebAssembly runtimes like Mozilla’s wasmtime and Fastly’s Lucet, to Node, or even the browser.
It also gives us sandboxing because the host can choose which wasi-core functions to pass in — so, which system calls to allow — on a program-by-program basis. This preserves security.
WASI gives us a way to extend this security even further. It brings in more concepts from capability-based security.
Traditionally, if code needs to open a file, it calls
open
with a string, which is the path name. Then the OS does a check to see if the code has permission (based on the user who started the program).With WASI, if you’re calling a function that needs to access a file, you have to pass in a file descriptor, which has permissions attached to it. This could be for the file itself, or for a directory that contains the file.
This way, you can’t have code that randomly asks to open
/etc/passwd
. Instead, the code can only operate on the directories that are passed in to it.
This makes it possible to safely give sandboxed code more access to different system calls — because the capabilities of these system calls can be limited.
And this happens on a module-by-module basis. By default, a module doesn’t have any access to file descriptors. But if code in one module has a file descriptor, it can choose to pass that file descriptor to functions it calls in other modules. Or it can create more limited versions of the file descriptor to pass to the other functions.
So the runtime passes in the file descriptors that an app can use to the top level code, and then file descriptors get propagated through the rest of the system on an as-needed basis.
This gets WebAssembly closer to the principle of least privilege, where a module can only access the exact resources it needs to do its job.
These concepts come from capability-oriented systems, like CloudABI and Capsicum. One problem with capability-oriented systems is that it is often hard to port code to them. But we think this problem can be solved.
If code already uses
openat
with relative file paths, compiling the code will just work.If code uses open and migrating to the
openat
style is too much up-front investment, WASI can provide an incremental solution. With libpreopen, you can create a list of file paths that the application legitimately needs access to. Then you can useopen
, but only with those paths.What’s next?
We think wasi-core is a good start. It preserves WebAssembly’s portability and security, providing a solid foundation for an ecosystem.
But there are still questions we’ll need to address after wasi-core is fully standardized. Those questions include:
- asynchronous I/O
- file watching
- file locking
This is just the beginning, so if you have ideas for how to solve these problems, join us!
全文摘自
[1] WASI 前瞻:https://zhuanlan.zhihu.com/p/105902805
[2] Mozilla 发布 WASI 计划,可在所有设备上运行 WebAssembly:https://www.infoq.cn/article/rkcuswctom5wc5*kowac
[3] 上面文章英文原文:https://www.infoq.com/news/2019/04/wasi-wasm-system-interface/
[4] Standardizing WASI: A system interface to run WebAssembly outside the web:https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/