1 mod test_helpers;
2
3 use crate::test_helpers::{run, run_with_stdout, LUCET_WASI_ROOT};
4 use lucet_wasi::{WasiCtx, WasiCtxBuilder};
5 use std::fs::File;
6 use std::path::Path;
7 use tempfile::TempDir;
8
9 #[test]
double_import()10 fn double_import() {
11 let ctx = WasiCtxBuilder::new();
12
13 let (exitcode, stdout) = run_with_stdout("duplicate_import.wat", ctx).unwrap();
14
15 assert_eq!(stdout, "duplicate import works!\n");
16 assert_eq!(exitcode, 0);
17 }
18
19 #[test]
hello()20 fn hello() {
21 let ctx = WasiCtxBuilder::new().args(&["hello"]);
22
23 let (exitcode, stdout) = run_with_stdout(
24 Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"),
25 ctx,
26 )
27 .unwrap();
28
29 assert_eq!(exitcode, 0);
30 assert_eq!(&stdout, "hello, wasi!\n");
31 }
32
33 #[test]
hello_args()34 fn hello_args() {
35 let ctx = WasiCtxBuilder::new().args(&["hello", "test suite"]);
36
37 let (exitcode, stdout) = run_with_stdout(
38 Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"),
39 ctx,
40 )
41 .unwrap();
42
43 assert_eq!(exitcode, 0);
44 assert_eq!(&stdout, "hello, test suite!\n");
45 }
46
47 #[test]
hello_env()48 fn hello_env() {
49 let ctx = WasiCtxBuilder::new()
50 .args(&["hello", "test suite"])
51 .env("GREETING", "goodbye");
52
53 let (exitcode, stdout) = run_with_stdout(
54 Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"),
55 ctx,
56 )
57 .unwrap();
58
59 assert_eq!(exitcode, 0);
60 assert_eq!(&stdout, "goodbye, test suite!\n");
61 }
62
63 #[test]
exitcode()64 fn exitcode() {
65 let ctx = WasiCtx::new(&["exitcode"]);
66
67 let exitcode = run("exitcode.c", ctx).unwrap();
68
69 assert_eq!(exitcode, 120);
70 }
71
72 #[test]
clock_getres()73 fn clock_getres() {
74 let ctx = WasiCtx::new(&["clock_getres"]);
75
76 let exitcode = run("clock_getres.c", ctx).unwrap();
77
78 assert_eq!(exitcode, 0);
79 }
80
81 #[test]
getrusage()82 fn getrusage() {
83 let ctx = WasiCtx::new(&["getrusage"]);
84
85 let exitcode = run("getrusage.c", ctx).unwrap();
86
87 assert_eq!(exitcode, 0);
88 }
89
90 #[test]
gettimeofday()91 fn gettimeofday() {
92 let ctx = WasiCtx::new(&["gettimeofday"]);
93
94 let exitcode = run("gettimeofday.c", ctx).unwrap();
95
96 assert_eq!(exitcode, 0);
97 }
98
99 #[test]
getentropy()100 fn getentropy() {
101 let ctx = WasiCtx::new(&["getentropy"]);
102
103 let exitcode = run("getentropy.c", ctx).unwrap();
104
105 assert_eq!(exitcode, 0);
106 }
107
108 #[test]
stdin()109 fn stdin() {
110 use std::io::Write;
111 use std::os::unix::io::FromRawFd;
112
113 let (pipe_out, pipe_in) = nix::unistd::pipe().expect("can create pipe");
114
115 let mut stdin_file = unsafe { File::from_raw_fd(pipe_in) };
116 write!(stdin_file, "hello from stdin!").expect("pipe write succeeds");
117 drop(stdin_file);
118
119 let ctx = unsafe { WasiCtxBuilder::new().args(&["stdin"]).raw_fd(0, pipe_out) };
120
121 let (exitcode, stdout) = run_with_stdout("stdin.c", ctx).unwrap();
122
123 assert_eq!(exitcode, 0);
124 assert_eq!(&stdout, "hello from stdin!");
125 }
126
127 #[test]
preopen_populates()128 fn preopen_populates() {
129 let tmpdir = TempDir::new().unwrap();
130 let preopen_host_path = tmpdir.path().join("preopen");
131 std::fs::create_dir(&preopen_host_path).unwrap();
132 let preopen_dir = File::open(preopen_host_path).unwrap();
133
134 let ctx = WasiCtxBuilder::new()
135 .args(&["preopen_populates"])
136 .preopened_dir(preopen_dir, "/preopen")
137 .build()
138 .expect("can build WasiCtx");
139
140 let exitcode = run("preopen_populates.c", ctx).unwrap();
141
142 drop(tmpdir);
143
144 assert_eq!(exitcode, 0);
145 }
146
147 #[test]
write_file()148 fn write_file() {
149 let tmpdir = TempDir::new().unwrap();
150 let preopen_host_path = tmpdir.path().join("preopen");
151 std::fs::create_dir(&preopen_host_path).unwrap();
152 let preopen_dir = File::open(&preopen_host_path).unwrap();
153
154 let ctx = WasiCtxBuilder::new()
155 .args(&["write_file"])
156 .preopened_dir(preopen_dir, "/sandbox")
157 .build()
158 .expect("can build WasiCtx");
159
160 let exitcode = run("write_file.c", ctx).unwrap();
161 assert_eq!(exitcode, 0);
162
163 let output = std::fs::read(preopen_host_path.join("output.txt")).unwrap();
164
165 assert_eq!(output.as_slice(), b"hello, file!");
166
167 drop(tmpdir);
168 }
169
170 #[test]
read_file()171 fn read_file() {
172 const MESSAGE: &'static str = "hello from file!";
173 let tmpdir = TempDir::new().unwrap();
174 let preopen_host_path = tmpdir.path().join("preopen");
175 std::fs::create_dir(&preopen_host_path).unwrap();
176
177 std::fs::write(preopen_host_path.join("input.txt"), MESSAGE).unwrap();
178
179 let preopen_dir = File::open(&preopen_host_path).unwrap();
180
181 let ctx = WasiCtxBuilder::new()
182 .args(&["read_file"])
183 .preopened_dir(preopen_dir, "/sandbox");
184
185 let (exitcode, stdout) = run_with_stdout("read_file.c", ctx).unwrap();
186 assert_eq!(exitcode, 0);
187
188 assert_eq!(&stdout, MESSAGE);
189
190 drop(tmpdir);
191 }
192
193 #[test]
read_file_twice()194 fn read_file_twice() {
195 const MESSAGE: &'static str = "hello from file!";
196 let tmpdir = TempDir::new().unwrap();
197 let preopen_host_path = tmpdir.path().join("preopen");
198 std::fs::create_dir(&preopen_host_path).unwrap();
199
200 std::fs::write(preopen_host_path.join("input.txt"), MESSAGE).unwrap();
201
202 let preopen_dir = File::open(&preopen_host_path).unwrap();
203
204 let ctx = WasiCtxBuilder::new()
205 .args(&["read_file_twice"])
206 .preopened_dir(preopen_dir, "/sandbox");
207
208 let (exitcode, stdout) = run_with_stdout("read_file_twice.c", ctx).unwrap();
209 assert_eq!(exitcode, 0);
210
211 let double_message = format!("{}{}", MESSAGE, MESSAGE);
212 assert_eq!(stdout, double_message);
213
214 drop(tmpdir);
215 }
216
217 #[test]
cant_dotdot()218 fn cant_dotdot() {
219 const MESSAGE: &'static str = "hello from file!";
220 let tmpdir = TempDir::new().unwrap();
221 let preopen_host_path = tmpdir.path().join("preopen");
222 std::fs::create_dir(&preopen_host_path).unwrap();
223
224 std::fs::write(
225 preopen_host_path.parent().unwrap().join("outside.txt"),
226 MESSAGE,
227 )
228 .unwrap();
229
230 let preopen_dir = File::open(&preopen_host_path).unwrap();
231
232 let ctx = WasiCtxBuilder::new()
233 .args(&["cant_dotdot"])
234 .preopened_dir(preopen_dir, "/sandbox")
235 .build()
236 .unwrap();
237
238 let exitcode = run("cant_dotdot.c", ctx).unwrap();
239 assert_eq!(exitcode, 0);
240
241 drop(tmpdir);
242 }
243
244 #[ignore] // needs fd_readdir
245 #[test]
notdir()246 fn notdir() {
247 const MESSAGE: &'static str = "hello from file!";
248 let tmpdir = TempDir::new().unwrap();
249 let preopen_host_path = tmpdir.path().join("preopen");
250 std::fs::create_dir(&preopen_host_path).unwrap();
251
252 std::fs::write(preopen_host_path.join("notadir"), MESSAGE).unwrap();
253
254 let preopen_dir = File::open(&preopen_host_path).unwrap();
255
256 let ctx = WasiCtxBuilder::new()
257 .args(&["notdir"])
258 .preopened_dir(preopen_dir, "/sandbox")
259 .build()
260 .unwrap();
261
262 let exitcode = run("notdir.c", ctx).unwrap();
263 assert_eq!(exitcode, 0);
264
265 drop(tmpdir);
266 }
267
268 #[test]
follow_symlink()269 fn follow_symlink() {
270 const MESSAGE: &'static str = "hello from file!";
271
272 let tmpdir = TempDir::new().unwrap();
273 let preopen_host_path = tmpdir.path().join("preopen");
274 let subdir1 = preopen_host_path.join("subdir1");
275 let subdir2 = preopen_host_path.join("subdir2");
276 std::fs::create_dir_all(&subdir1).unwrap();
277 std::fs::create_dir_all(&subdir2).unwrap();
278
279 std::fs::write(subdir1.join("input.txt"), MESSAGE).unwrap();
280
281 std::os::unix::fs::symlink("../subdir1/input.txt", subdir2.join("input_link.txt")).unwrap();
282
283 let preopen_dir = File::open(&preopen_host_path).unwrap();
284
285 let ctx = WasiCtxBuilder::new()
286 .args(&["follow_symlink"])
287 .preopened_dir(preopen_dir, "/sandbox");
288
289 let (exitcode, stdout) = run_with_stdout("follow_symlink.c", ctx).unwrap();
290 assert_eq!(exitcode, 0);
291 assert_eq!(&stdout, MESSAGE);
292
293 drop(tmpdir);
294 }
295
296 #[test]
symlink_loop()297 fn symlink_loop() {
298 let tmpdir = TempDir::new().unwrap();
299 let preopen_host_path = tmpdir.path().join("preopen");
300 let subdir1 = preopen_host_path.join("subdir1");
301 let subdir2 = preopen_host_path.join("subdir2");
302 std::fs::create_dir_all(&subdir1).unwrap();
303 std::fs::create_dir_all(&subdir2).unwrap();
304
305 std::os::unix::fs::symlink("../subdir1/loop1", subdir2.join("loop2")).unwrap();
306 std::os::unix::fs::symlink("../subdir2/loop2", subdir1.join("loop1")).unwrap();
307
308 let preopen_dir = File::open(&preopen_host_path).unwrap();
309
310 let ctx = WasiCtxBuilder::new()
311 .args(&["symlink_loop"])
312 .preopened_dir(preopen_dir, "/sandbox")
313 .build()
314 .unwrap();
315
316 let exitcode = run("symlink_loop.c", ctx).unwrap();
317 assert_eq!(exitcode, 0);
318
319 drop(tmpdir);
320 }
321
322 #[test]
symlink_escape()323 fn symlink_escape() {
324 const MESSAGE: &'static str = "hello from file!";
325
326 let tmpdir = TempDir::new().unwrap();
327 let preopen_host_path = tmpdir.path().join("preopen");
328 let subdir = preopen_host_path.join("subdir");
329 std::fs::create_dir_all(&subdir).unwrap();
330
331 std::fs::write(
332 preopen_host_path.parent().unwrap().join("outside.txt"),
333 MESSAGE,
334 )
335 .unwrap();
336 std::os::unix::fs::symlink("../../outside.txt", subdir.join("outside.txt")).unwrap();
337
338 let preopen_dir = File::open(&preopen_host_path).unwrap();
339
340 let ctx = WasiCtxBuilder::new()
341 .args(&["symlink_escape"])
342 .preopened_dir(preopen_dir, "/sandbox")
343 .build()
344 .unwrap();
345
346 let exitcode = run("symlink_escape.c", ctx).unwrap();
347 assert_eq!(exitcode, 0);
348
349 drop(tmpdir);
350 }
351
352 #[test]
pseudoquine()353 fn pseudoquine() {
354 let examples_dir = Path::new(LUCET_WASI_ROOT).join("examples");
355 let pseudoquine_c = examples_dir.join("pseudoquine.c");
356
357 let ctx = WasiCtxBuilder::new()
358 .args(&["pseudoquine"])
359 .preopened_dir(File::open(examples_dir).unwrap(), "/examples");
360
361 let (exitcode, stdout) = run_with_stdout(&pseudoquine_c, ctx).unwrap();
362
363 assert_eq!(exitcode, 0);
364
365 let expected = std::fs::read_to_string(&pseudoquine_c).unwrap();
366
367 assert_eq!(stdout, expected);
368 }
369
370 #[test]
poll()371 fn poll() {
372 let ctx = WasiCtxBuilder::new().args(&["poll"]).build().unwrap();
373 let exitcode = run("poll.c", ctx).unwrap();
374 assert_eq!(exitcode, 0);
375 }
376
377 #[test]
stat()378 fn stat() {
379 let tmpdir = TempDir::new().unwrap();
380 let preopen_host_path = tmpdir.path().join("preopen");
381 std::fs::create_dir(&preopen_host_path).unwrap();
382 let preopen_dir = File::open(&preopen_host_path).unwrap();
383 let ctx = WasiCtxBuilder::new()
384 .args(&["stat"])
385 .preopened_dir(preopen_dir, "/sandbox")
386 .build()
387 .expect("can build WasiCtx");
388 let exitcode = run("stat.c", ctx).unwrap();
389 assert_eq!(exitcode, 0);
390 }
391
392 #[test]
fs()393 fn fs() {
394 let tmpdir = TempDir::new().unwrap();
395 let preopen_host_path = tmpdir.path().join("preopen");
396 std::fs::create_dir(&preopen_host_path).unwrap();
397 let preopen_dir = File::open(&preopen_host_path).unwrap();
398 let ctx = WasiCtxBuilder::new()
399 .args(&["stat"])
400 .preopened_dir(preopen_dir, "/sandbox")
401 .build()
402 .expect("can build WasiCtx");
403 let exitcode = run("fs.c", ctx).unwrap();
404 assert_eq!(exitcode, 0);
405 }
406