1*b2fefe77SDan Gohman# WASI tutorial 2*b2fefe77SDan Gohman 3*b2fefe77SDan GohmanLet's start with a simple C program which performs a file copy, which will 4*b2fefe77SDan Gohmanshow to compile and run programs, as well as perform simple sandbox 5*b2fefe77SDan Gohmanconfiguration. The C code here uses standard POSIX APIs, and doesn't have 6*b2fefe77SDan Gohmanany knowledge of WASI, WebAssembly, or sandboxing. 7*b2fefe77SDan Gohman 8*b2fefe77SDan Gohman```c 9*b2fefe77SDan Gohman#include <stdio.h> 10*b2fefe77SDan Gohman#include <string.h> 11*b2fefe77SDan Gohman#include <stdlib.h> 12*b2fefe77SDan Gohman#include <unistd.h> 13*b2fefe77SDan Gohman#include <fcntl.h> 14*b2fefe77SDan Gohman#include <errno.h> 15*b2fefe77SDan Gohman 16*b2fefe77SDan Gohmanint 17*b2fefe77SDan Gohmanmain(int argc, char **argv) { 18*b2fefe77SDan Gohman int n, m; 19*b2fefe77SDan Gohman char buf[BUFSIZ]; 20*b2fefe77SDan Gohman 21*b2fefe77SDan Gohman if (argc != 3) { 22*b2fefe77SDan Gohman fprintf(stderr, "usage: %s <from> <to>\n", argv[0]); 23*b2fefe77SDan Gohman exit(1); 24*b2fefe77SDan Gohman } 25*b2fefe77SDan Gohman 26*b2fefe77SDan Gohman int in = open(argv[1], O_RDONLY); 27*b2fefe77SDan Gohman if (in < 0) { 28*b2fefe77SDan Gohman fprintf(stderr, "error opening input %s: %s\n", argv[1], strerror(errno)); 29*b2fefe77SDan Gohman exit(1); 30*b2fefe77SDan Gohman } 31*b2fefe77SDan Gohman 32*b2fefe77SDan Gohman int out = open(argv[2], O_WRONLY | O_CREAT, 0660); 33*b2fefe77SDan Gohman if (out < 0) { 34*b2fefe77SDan Gohman fprintf(stderr, "error opening output %s: %s\n", argv[2], strerror(errno)); 35*b2fefe77SDan Gohman exit(1); 36*b2fefe77SDan Gohman } 37*b2fefe77SDan Gohman 38*b2fefe77SDan Gohman while ((n = read(in, buf, BUFSIZ)) > 0) { 39*b2fefe77SDan Gohman while (n > 0) { 40*b2fefe77SDan Gohman m = write(out, buf, n); 41*b2fefe77SDan Gohman if (m < 0) { 42*b2fefe77SDan Gohman fprintf(stderr, "write error: %s\n", strerror(errno)); 43*b2fefe77SDan Gohman exit(1); 44*b2fefe77SDan Gohman } 45*b2fefe77SDan Gohman n -= m; 46*b2fefe77SDan Gohman } 47*b2fefe77SDan Gohman } 48*b2fefe77SDan Gohman 49*b2fefe77SDan Gohman if (n < 0) { 50*b2fefe77SDan Gohman fprintf(stderr, "read error: %s\n", strerror(errno)); 51*b2fefe77SDan Gohman exit(1); 52*b2fefe77SDan Gohman } 53*b2fefe77SDan Gohman 54*b2fefe77SDan Gohman return EXIT_SUCCESS; 55*b2fefe77SDan Gohman} 56*b2fefe77SDan Gohman``` 57*b2fefe77SDan Gohman 58*b2fefe77SDan GohmanWe'll put this source in a file called `demo.c`. 59*b2fefe77SDan Gohman 60*b2fefe77SDan GohmanThe [wasi-sdk](https://github.com/CraneStation/wasi-sdk/releases) provides a clang 61*b2fefe77SDan Gohmanwhich is configured to target WASI and use the WASI sysroot by default, so we can 62*b2fefe77SDan Gohmancompile our program like so: 63*b2fefe77SDan Gohman 64*b2fefe77SDan Gohman``` 65*b2fefe77SDan Gohman$ clang demo.c 66*b2fefe77SDan Gohman``` 67*b2fefe77SDan Gohman 68*b2fefe77SDan GohmanA few things to note here. First, this is just regular clang, configured to use 69*b2fefe77SDan Gohmana WebAssembly target and sysroot. The name `a.out` is the traditional default 70*b2fefe77SDan Gohmanoutput name that C compilers use, and can be overridden with the "-o" flag in the 71*b2fefe77SDan Gohmanusual way. And, the output of clang here is a standard WebAssembly module: 72*b2fefe77SDan Gohman 73*b2fefe77SDan Gohman``` 74*b2fefe77SDan Gohman$ file a.out 75*b2fefe77SDan Gohmana.out: WebAssembly (wasm) binary module version 0x1 (MVP) 76*b2fefe77SDan Gohman``` 77*b2fefe77SDan Gohman 78*b2fefe77SDan GohmanIt's a single file containing a self-contained wasm module, that doesn't require 79*b2fefe77SDan Gohmanany supporting JS code. 80*b2fefe77SDan Gohman 81*b2fefe77SDan GohmanWe can execute it with wasmtime directly, like so: 82*b2fefe77SDan Gohman 83*b2fefe77SDan Gohman``` 84*b2fefe77SDan Gohman$ wasmtime a.out 85*b2fefe77SDan Gohmanusage: a.out <from> <to> 86*b2fefe77SDan Gohman``` 87*b2fefe77SDan Gohman 88*b2fefe77SDan GohmanOk, this program needs some command-line arguments. So let's give it some: 89*b2fefe77SDan Gohman 90*b2fefe77SDan Gohman``` 91*b2fefe77SDan Gohman$ echo hello world > test.txt 92*b2fefe77SDan Gohman$ wasmtime a.out test.txt /tmp/somewhere.txt 93*b2fefe77SDan Gohmanerror opening input test.txt: Capabilities insufficient 94*b2fefe77SDan Gohman``` 95*b2fefe77SDan Gohman 96*b2fefe77SDan GohmanAha, now we're seeing the sandboxing in action. This program is attempting to 97*b2fefe77SDan Gohmanaccess a file by the name of `test.txt`, however it hasn't been given the 98*b2fefe77SDan Gohmancapability to do so. 99*b2fefe77SDan Gohman 100*b2fefe77SDan GohmanSo let's give it capabilities to access files in the requisite directories: 101*b2fefe77SDan Gohman 102*b2fefe77SDan Gohman``` 103*b2fefe77SDan Gohman$ wasmtime --dir=. --dir=/tmp a.out test.txt /tmp/somewhere.txt 104*b2fefe77SDan Gohman$ cat /tmp/somewhere.txt 105*b2fefe77SDan Gohmanhello world 106*b2fefe77SDan Gohman``` 107*b2fefe77SDan Gohman 108*b2fefe77SDan GohmanNow our program runs as expected! 109*b2fefe77SDan Gohman 110*b2fefe77SDan GohmanAs a brief aside, note that we used the path `.` above to grant the program 111*b2fefe77SDan Gohmanaccess to the current directory. This is needed because the mapping from 112*b2fefe77SDan Gohmanpaths to associated capabilities is performed by libc, so it's part of the 113*b2fefe77SDan GohmanWebAssembly program, and we don't expose the actual current working 114*b2fefe77SDan Gohmandirectory to the WebAssembly program. So providing a full path doesn't work: 115*b2fefe77SDan Gohman 116*b2fefe77SDan Gohman``` 117*b2fefe77SDan Gohman$ wasmtime --dir=$PWD --dir=/tmp a.out test.txt /tmp/somewhere.txt 118*b2fefe77SDan Gohman$ cat /tmp/somewhere.txt 119*b2fefe77SDan Gohmanerror opening input test.txt: Capabilities insufficient 120*b2fefe77SDan Gohman``` 121*b2fefe77SDan Gohman 122*b2fefe77SDan GohmanSo, we always have to use `.` to refer to the current directory. 123*b2fefe77SDan Gohman 124*b2fefe77SDan GohmanSpeaking of `.`, what about `..`? Does that give programs a way to break 125*b2fefe77SDan Gohmanout of the sandbox? Let's see: 126*b2fefe77SDan Gohman 127*b2fefe77SDan Gohman``` 128*b2fefe77SDan Gohman$ wasmtime --dir=. --dir=/tmp a.out test.txt /tmp/../etc/passwd 129*b2fefe77SDan Gohman$ cat /tmp/somewhere.txt 130*b2fefe77SDan Gohmanerror opening output /tmp/../etc/passwd: Capabilities insufficient 131*b2fefe77SDan Gohman``` 132*b2fefe77SDan Gohman 133*b2fefe77SDan GohmanThe sandbox says no. And note that this is the capabilities system saying no 134*b2fefe77SDan Gohmanhere ("Capabilities insufficient"), rather than Unix access controls 135*b2fefe77SDan Gohman("Permission denied"). Even if the user running wasmtime had write access to 136*b2fefe77SDan Gohman`/etc/passwd`, WASI programs don't have the capability to access files outside 137*b2fefe77SDan Gohmanof the directories they've been granted. This is true when resolving symbolic 138*b2fefe77SDan Gohmanlinks as well. 139*b2fefe77SDan Gohman 140*b2fefe77SDan GohmanWasmtime also has the ability to remap directories, with the `--mapdir` 141*b2fefe77SDan Gohmancommand-line option: 142*b2fefe77SDan Gohman 143*b2fefe77SDan Gohman``` 144*b2fefe77SDan Gohman$ wasmtime --dir=. --mapdir=/tmp:/var/tmp a.out test.txt /tmp/somewhere.txt 145*b2fefe77SDan Gohman$ cat /var/tmp/somewhere.txt 146*b2fefe77SDan Gohmanhello world 147*b2fefe77SDan Gohman``` 148*b2fefe77SDan Gohman 149*b2fefe77SDan GohmanThis maps the name `/tmp` within the WebAssembly program to `/var/tmp` in the 150*b2fefe77SDan Gohmanhost filesystem. So the WebAssembly program itself never sees the `/var/tmp` path, 151*b2fefe77SDan Gohmanbut that's where the output file goes. 152*b2fefe77SDan Gohman 153*b2fefe77SDan GohmanSee [here](WASI-capabilities.md) for more information on the capability-based 154*b2fefe77SDan Gohmansecurity model. 155*b2fefe77SDan Gohman 156*b2fefe77SDan GohmanThe capability model is very powerful, and what's shown here is just the beginning. 157*b2fefe77SDan GohmanIn the future, we'll be exposing much more functionality, including finer-grained 158*b2fefe77SDan Gohmancapabilities, capabilities for network ports, and the ability for applications to 159*b2fefe77SDan Gohmanexplicitly request capabilities. 160