xref: /wasmtime-44.0.1/docs/WASI-tutorial.md (revision b2fefe77)
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