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