Uvwasi
WASI syscall API built atop libuv
Install / Use
/learn @nodejs/UvwasiREADME
uvwasi
This project does not currently provide the comprehensive file system security properties provided by some WASI runtimes. Full support for secure file system sandboxing may or may not be implemented in future. In the mean time, do not rely on it to run untrusted code.
uvwasi implements the [WASI][] system call API, so that WebAssembly
runtimes can easily implement WASI calls. Under the hood, uvwasi
leverages [libuv][] where possible for maximum portability.
|
WebAssembly code | WebAssembly application code
| |
| v
| WASI syscalls (inserted by compiler toolchain)
| |
------------------------------+ |
| v
WebAssembly runtime (Node.js) | uvwasi (implementation of WASI)
| |
| v
| libuv
| |
| v
| platform-specific calls
|
(Hence uvwasi isn't for making C-programs-that-use-libuv-APIs execute on WASI runtimes. That would either be a new platform added by libuv, or done through POSIX emulation by the Emscripten or wasi-sdk toolchains.)
Building Locally
To build with CMake:
$ mkdir -p out/cmake ; cd out/cmake # create build directory
$ cmake ../.. -DBUILD_TESTING=ON # generate project with test
$ cmake --build . # build
$ ctest -C Debug --output-on-failure # run tests
Example Usage
#include <stdlib.h>
#include <assert.h>
#include "uv.h"
#include "uvwasi.h"
int main(void) {
uvwasi_t uvwasi;
uvwasi_options_t init_options;
uvwasi_errno_t err;
/* Setup the initialization options. */
init_options.in = 0;
init_options.out = 1;
init_options.err = 2;
init_options.fd_table_size = 3;
init_options.argc = 3;
init_options.argv = calloc(3, sizeof(char*));
init_options.argv[0] = "--foo=bar";
init_options.argv[1] = "-baz";
init_options.argv[2] = "100";
init_options.envp = NULL;
init_options.preopenc = 1;
init_options.preopens = calloc(1, sizeof(uvwasi_preopen_t));
init_options.preopens[0].mapped_path = "/var";
init_options.preopens[0].real_path = ".";
init_options.allocator = NULL;
/* Initialize the sandbox. */
err = uvwasi_init(&uvwasi, &init_options);
assert(err == UVWASI_ESUCCESS);
/* TODO(cjihrig): Show an example system call or two. */
/* Clean up resources. */
uvwasi_destroy(&uvwasi);
return 0;
}
API
The WASI API is versioned. This documentation is based on the WASI [preview 1][]
snapshot. uvwasi implements the WASI system call API with the following
additions/modifications:
- Each system call takes an additional
uvwasi_t*as its first argument. Theuvwasi_tis the sandbox under which system calls are issued. Eachuvwasi_tcan have different command line arguments, environment variables, preopened directories, file descriptor mappings, etc. This allows one controlling process to host multiple WASI applications simultaneously. - Each system call returns a
uvwasi_errno_t. This appears to be expected of WASI system calls, but it is not explicitly part of the official API docs. This detail is explicitly documented here. - Additional functions and data types are provided for interacting with WASI
sandboxes and the
uvwasilibrary. These APIs are documented in the Unofficial APIs section below.
Unofficial APIs
This section contains data types and functions for working with uvwasi. They
are not part of the official WASI API, but are used to embed uvwasi.
<a href="#version_major" name="version_major"></a>UVWASI_VERSION_MAJOR
The major release version of the uvwasi library. uvwasi follows semantic
versioning. Changes to this value represent breaking changes in the public API.
<a href="#version_minor" name="version_minor"></a>UVWASI_VERSION_MINOR
The minor release version of the uvwasi library. uvwasi follows semantic
versioning. Changes to this value represent feature additions in the public API.
<a href="#version_patch" name="version_patch"></a>UVWASI_VERSION_PATCH
The patch release version of the uvwasi library. uvwasi follows semantic
versioning. Changes to this value represent bug fixes in the public API.
<a href="#version_hex" name="version_hex"></a>UVWASI_VERSION_HEX
The major, minor, and patch versions of the uvwasi library encoded as a single
integer value.
<a href="#version_string" name="version_string"></a>UVWASI_VERSION_STRING
The major, minor, and patch versions of the uvwasi library encoded as a
version string.
<a href="#version_wasi" name="version_wasi"></a>UVWASI_VERSION_WASI
The version of the WASI API targeted by uvwasi.
<a href="#uvwasi_t" name="uvwasi_t"></a>uvwasi_t
An individual WASI sandbox instance.
typedef struct uvwasi_s {
struct uvwasi_fd_table_t fds;
uvwasi_size_t argc;
char** argv;
char* argv_buf;
uvwasi_size_t argv_buf_size;
uvwasi_size_t envc;
char** env;
char* env_buf;
uvwasi_size_t env_buf_size;
} uvwasi_t;
<a href="#uvwasi_preopen_t" name="uvwasi_preopen_t"></a>uvwasi_preopen_t
A data structure used to map a directory path within a WASI sandbox to a directory path on the WASI host platform.
typedef struct uvwasi_preopen_s {
char* mapped_path;
char* real_path;
} uvwasi_preopen_t;
<a href="#uvwasi_options_t" name="uvwasi_options_t"></a>uvwasi_options_t
A data structure used to pass configuration options to uvwasi_init().
typedef struct uvwasi_options_s {
uvwasi_size_t fd_table_size;
uvwasi_size_t preopenc;
uvwasi_preopen_t* preopens;
uvwasi_size_t argc;
char** argv;
char** envp;
uvwasi_fd_t in;
uvwasi_fd_t out;
uvwasi_fd_t err;
const uvwasi_mem_t* allocator;
} uvwasi_options_t;
<a href="#uvwasi_init" name="uvwasi_init"></a>uvwasi_init()
Initializes a sandbox represented by a uvwasi_t using the options represented
by a uvwasi_options_t.
Inputs:
-
<a href="#uvwasi_init.uvwasi" name="uvwasi_init.uvwasi"></a><code>__wasi_t <strong>uvwasi</strong></code>
The sandbox to initialize.
-
<a href="#uvwasi_init.options" name="uvwasi_init.options"></a><code>__wasi_options_t <strong>options</strong></code>
Configuration options used when initializing the sandbox.
Outputs:
- None
Returns:
-
<a href="#uvwasi_init.return" name="uvwasi_init.return"></a><code>__wasi_errno_t <strong>errno</strong></code>
A WASI errno.
<a href="#uvwasi_destroy" name="uvwasi_destroy"></a>uvwasi_destroy()
Cleans up resources related to a WASI sandbox. This function notably does not return an error code.
Inputs:
-
<a href="#uvwasi_destroy.uvwasi" name="uvwasi_destroy.uvwasi"></a><code>__wasi_t <strong>uvwasi</strong></code>
The sandbox to clean up.
Outputs:
- None
Returns:
- None
System Calls
This section has been adapted from the official WASI API documentation.
uvwasi_args_get()uvwasi_args_sizes_get()uvwasi_clock_res_get()uvwasi_clock_time_get()uvwasi_environ_get()uvwasi_environ_sizes_get()uvwasi_fd_advise()uvwasi_fd_allocate()uvwasi_fd_close()uvwasi_fd_datasync()uvwasi_fd_fdstat_get()uvwasi_fd_fdstat_set_flags()uvwasi_fd_fdstat_set_rights()uvwasi_fd_filestat_get()uvwasi_fd_filestat_set_size()uvwasi_fd_filestat_set_times()uvwasi_fd_pread()uvwasi_fd_prestat_get()uvwasi_fd_prestat_dir_name()uvwasi_fd_pwrite()uvwasi_fd_read()uvwasi_fd_readdir()uvwasi_fd_renumber()uvwasi_fd_seek()uvwasi_fd_sync()uvwasi_fd_tell()uvwasi_fd_write()uvwasi_path_create_directory()uvwasi_path_filestat_get()uvwasi_path_filestat_set_times()uvwasi_path_link()uvwasi_path_open()uvwasi_path_readlink()uvwasi_path_remove_directory()uvwasi_path_rename()uvwasi_path_symlink()uvwasi_path_unlink_file()uvwasi_poll_oneoff()uvwasi_proc_exit()uvwasi_proc_raise()uvwasi_random_get()uvwasi_sched_yield()uvwasi_sock_recv()uvwasi_sock_send()uvwasi_sock_shutdown()
<a href="#args_get" name="args_get"></a>uvwasi_args_get()
Read command-line argument data.
The sizes of the buffers should match that returned by uvwasi_args_sizes_get().
Inputs:
-
<a href="#args_get.argv" name="args_get.argv"></a><code>char **<strong>argv</strong></code>
A pointer to a buffer to write the argument pointers.
-
<a href="#args_get.argv_buf" name="args_get.argv_buf"></a><code>char *<strong>argv_buf</strong></code>
A pointer to a buffer to write the argument strin
