xref: /openbsd-src/regress/sys/kern/unveil/syscalls.c (revision 2c5685b9db4928888a1a2384f8eaf0070cec2f29)
1 /*	$OpenBSD: syscalls.c,v 1.37 2024/09/03 04:59:03 anton Exp $	*/
2 
3 /*
4  * Copyright (c) 2017-2019 Bob Beck <beck@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <sys/mount.h>
24 
25 #include "unveil.h"
26 
27 /* all the things unless we override */
28 const char *uv_flags = "rwxc";
29 
30 static void
31 do_unveil(void)
32 {
33 	if (unveil(uv_dir1, uv_flags) == -1)
34                 err(1, "%s:%d - unveil", __FILE__, __LINE__);
35 	if (unveil(uv_file1, uv_flags) == -1)
36                 err(1, "%s:%d - unveil", __FILE__, __LINE__);
37 }
38 
39 static void
40 do_unveil2(void)
41 {
42 	if (unveil(uv_dir1, uv_flags) == -1)
43                 err(1, "%s:%d - unveil", __FILE__, __LINE__);
44 }
45 
46 static int
47 test_openat(int do_uv)
48 {
49 	int slashbefore;
50 	int dirfd1before;
51 	int dirfd2before;
52 	int dirfd1after;
53 	int dirfd2after;
54 	UV_SHOULD_SUCCEED(((slashbefore = open("/", O_RDONLY | O_DIRECTORY)) == -1), "open");
55 	UV_SHOULD_SUCCEED(((dirfd1before = open(uv_dir1, O_RDONLY | O_DIRECTORY)) == -1), "open");
56 	UV_SHOULD_SUCCEED(((dirfd2before = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open");
57 	if (do_uv) {
58 	  	printf("testing openat\n");
59 		do_unveil();
60 	}
61 	UV_SHOULD_SUCCEED(((dirfd1after = open(uv_dir1, O_RDONLY | O_DIRECTORY)) == -1), "open");
62 	UV_SHOULD_ENOENT(((dirfd2after = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open");
63 
64 	UV_SHOULD_ENOENT((openat(slashbefore, "etc/hosts", O_RDONLY) == -1), "openat");
65 	UV_SHOULD_SUCCEED((openat(slashbefore, uv_file1, O_RDWR) == -1), "openat");
66 	UV_SHOULD_ENOENT((openat(slashbefore, uv_file2, O_RDWR) == -1), "openat");
67 
68 	UV_SHOULD_ENOENT((openat(dirfd1before, "/etc/hosts", O_RDONLY) == -1), "openat");
69 	UV_SHOULD_SUCCEED((openat(dirfd1before, "hooray", O_RDWR|O_CREAT, 0644) == -1), "openat");
70 	UV_SHOULD_SUCCEED((openat(dirfd1before, uv_file1, O_RDWR|O_CREAT, 0644) == -1), "openat");
71 	UV_SHOULD_ENOENT((openat(dirfd1before, uv_file2, O_RDWR|O_CREAT, 0644) == -1), "openat");
72 
73 	UV_SHOULD_ENOENT((openat(dirfd2before, "/etc/hosts", O_RDONLY) == -1), "openat");
74 	UV_SHOULD_ENOENT((openat(dirfd2before, "hooray", O_RDWR|O_CREAT, 0644) == -1), "openat");
75 	UV_SHOULD_SUCCEED((openat(dirfd2before, uv_file1, O_RDWR|O_CREAT, 0644) == -1), "openat");
76 	UV_SHOULD_ENOENT((openat(dirfd2before, uv_file2, O_RDWR|O_CREAT, 0644) == -1), "openat");
77 
78 	UV_SHOULD_ENOENT((openat(dirfd1after, "/etc/hosts", O_RDONLY) == -1), "openat");
79 	UV_SHOULD_SUCCEED((openat(dirfd1after, "hooray", O_RDWR|O_CREAT, 0644) == -1), "openat");
80 	UV_SHOULD_SUCCEED((openat(dirfd1after, uv_file1, O_RDWR|O_CREAT, 0644) == -1), "openat");
81 	UV_SHOULD_ENOENT((openat(dirfd1after, uv_file2, O_RDWR|O_CREAT, 0644) == -1), "openat");
82 
83 	UV_SHOULD_SUCCEED(((dirfd2after = openat(dirfd1after, "subdir",  O_RDONLY | O_DIRECTORY)) == -1), "openat");
84 	UV_SHOULD_SUCCEED((openat(dirfd2after, "../derp", O_RDWR|O_CREAT, 0644) == -1), "openat");
85 	UV_SHOULD_ENOENT((openat(dirfd2after, "../../derpyluvs", O_RDWR|O_CREAT, 0644) == -1), "openat");
86 	UV_SHOULD_ENOENT((openat(dirfd2after, "/etc/hosts", O_RDONLY) == -1), "openat");
87 	UV_SHOULD_SUCCEED((openat(dirfd2after, "hooray", O_RDWR|O_CREAT, 0644) == -1), "openat");
88 	UV_SHOULD_SUCCEED((openat(dirfd2after, uv_file1, O_RDWR|O_CREAT, 0644) == -1), "openat");
89 	UV_SHOULD_ENOENT((openat(dirfd2after, uv_file2, O_RDWR|O_CREAT, 0644) == -1), "openat");
90 	return 0;
91 }
92 
93 
94 
95 static int
96 test_open(int do_uv)
97 {
98 	char filename[256];
99 	int dirfd;
100 	int dirfd2;
101 	int dirfd3;
102 
103 
104 	UV_SHOULD_SUCCEED(((dirfd = open("/", O_RDONLY | O_DIRECTORY)) == -1), "open");
105 	UV_SHOULD_SUCCEED(((dirfd2 = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open");
106 	if (do_uv) {
107 		printf("testing open\n");
108 		do_unveil();
109 		if (unveil("/tmp/alpha", uv_flags) == -1)
110 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
111 		if (unveil("/tmp/bravo", uv_flags) == -1)
112 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
113 		if (unveil("/tmp/charlie", uv_flags) == -1)
114 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
115 		if (unveil("/tmp/delta", uv_flags) == -1)
116 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
117 		if (unveil("/tmp/echo", uv_flags) == -1)
118 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
119 		if (unveil("/tmp/foxtrot", uv_flags) == -1)
120 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
121 		if (unveil("/tmp/golf", uv_flags) == -1)
122 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
123 		if (unveil("/tmp/hotel", uv_flags) == -1)
124 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
125 		if (unveil("/tmp/india", uv_flags) == -1)
126 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
127 		if (unveil("/tmp/juliet", uv_flags) == -1)
128 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
129 		if (unveil("/tmp/kilo", uv_flags) == -1)
130 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
131 		if (unveil("/tmp/lima", uv_flags) == -1)
132 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
133 		if (unveil("/tmp/money", uv_flags) == -1)
134 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
135 		if (unveil("/tmp/november", uv_flags) == -1)
136 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
137 		if (unveil("/tmp/oscar", uv_flags) == -1)
138 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
139 		if (unveil("/tmp/papa", uv_flags) == -1)
140 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
141 		if (unveil("/tmp/quebec", uv_flags) == -1)
142 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
143 		if (unveil("/tmp/romeo", uv_flags) == -1)
144 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
145 		if (unveil("/tmp/sierra", uv_flags) == -1)
146 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
147 		if (unveil("/tmp/tango", uv_flags) == -1)
148 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
149 		if (unveil("/tmp/uniform", uv_flags) == -1)
150 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
151 		if (unveil("/tmp/victor", uv_flags) == -1)
152 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
153 		if (unveil("/tmp/whiskey", uv_flags) == -1)
154 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
155 		if (unveil("/tmp/xray", uv_flags) == -1)
156 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
157 		if (unveil("/tmp/yankee", uv_flags) == -1)
158 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
159 		if (unveil("/tmp/zulu", uv_flags) == -1)
160 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
161 	}
162 	UV_SHOULD_SUCCEED((pledge("unveil stdio rpath cpath wpath exec", NULL) == -1), "pledge");
163 
164 	UV_SHOULD_ENOENT((open(uv_file2, O_RDWR) == -1), "open");
165 	UV_SHOULD_ENOENT(((dirfd3= open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open");
166 
167 	UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open");
168 	if (!do_uv) {
169 		/* Unlink the unveiled file and make it again */
170 		UV_SHOULD_SUCCEED((unlink(uv_file1) == -1), "unlink");
171 		UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR|O_CREAT, 0644) == -1), "open");
172 	}
173 	sleep(1);
174 	UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open");
175 	UV_SHOULD_ENOENT((open(uv_file2, O_RDWR) == -1), "open");
176 	(void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir1, "newfile");
177 	UV_SHOULD_SUCCEED((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open");
178 	(void) snprintf(filename, sizeof(filename), "/%s/%s", uv_dir1, "doubleslash");
179 	UV_SHOULD_SUCCEED((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open");
180 	(void) snprintf(filename, sizeof(filename), "/%s//%s", uv_dir1, "doubleslash2");
181 	UV_SHOULD_SUCCEED((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open");
182 
183 	(void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir2, "newfile");
184 	UV_SHOULD_ENOENT((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open");
185 
186 	if (do_uv) {
187 		printf("testing flag escalation\n");
188 		if (unveil(uv_file1, "x") == -1)
189 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
190 		if (unveil(uv_file1, "rx") == -1)
191 			if (errno != EPERM)
192 				err(1, "%s:%d - unveil", __FILE__,
193 				    __LINE__);
194 	}
195 	return 0;
196 }
197 
198 static int
199 test_opendir(int do_uv)
200 {
201 	char filename[256];
202 	if (do_uv) {
203 		printf("testing opendir\n");
204 		do_unveil();
205 	}
206 	UV_SHOULD_SUCCEED((opendir(uv_dir1) == NULL), "opendir");
207 	UV_SHOULD_ENOENT((opendir(uv_dir2) == NULL), "opendir");
208 	(void) snprintf(filename, sizeof(filename), "/%s/.", uv_dir1);
209 	UV_SHOULD_SUCCEED((opendir(filename) == NULL), "opendir");
210 	(void) snprintf(filename, sizeof(filename), "/%s/..", uv_dir1);
211 	UV_SHOULD_ENOENT((opendir(filename) == NULL), "opendir");
212 	(void) snprintf(filename, sizeof(filename), "/%s/subdir", uv_dir1);
213 	UV_SHOULD_SUCCEED((opendir(filename) == NULL), "opendir");
214 	(void) snprintf(filename, sizeof(filename), "/%s/subdir/../subdir", uv_dir1);
215 	UV_SHOULD_SUCCEED((opendir(filename) == NULL), "opendir");
216 	(void) snprintf(filename, sizeof(filename), "/%s/../../%s/subdir", uv_dir1, uv_dir1);
217 	UV_SHOULD_SUCCEED((opendir(filename) == NULL), "opendir");
218 	(void) snprintf(filename, sizeof(filename), "/%s/subdir", uv_dir2);
219 	UV_SHOULD_ENOENT((opendir(filename) == NULL), "opendir");
220 	UV_SHOULD_ENOENT((opendir(filename) == NULL), "opendir");
221 	(void) snprintf(filename, sizeof(filename), "%s/../..%s/subdir", uv_dir1, uv_dir2);
222 	UV_SHOULD_ENOENT((opendir(filename) == NULL), "opendir");
223 	return 0;
224 }
225 
226 static int
227 test_realpath(int do_uv)
228 {
229 	char buf[PATH_MAX];
230 	if (do_uv) {
231 		printf("testing realpath\n");
232 		do_unveil();
233 	}
234 	UV_SHOULD_SUCCEED((realpath(uv_dir1, buf) == NULL), "realpath");
235 	UV_SHOULD_ENOENT((realpath(uv_dir2, buf) == NULL), "realpath");
236 	return 0;
237 }
238 
239 static int
240 test_r(int do_uv)
241 {
242 	if (do_uv) {
243 		printf("testing \"r\"\n");
244 		if (unveil(uv_file1, "r") == -1)
245 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
246 		if (unveil("/", "") == -1)
247 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
248 	}
249 	UV_SHOULD_SUCCEED((open(uv_file1, O_RDONLY) == -1), "open");
250 	UV_SHOULD_EACCES((open(uv_file1, O_RDWR) == -1), "open");
251 	return 0;
252 }
253 
254 static int
255 test_rw(int do_uv)
256 {
257 	if (do_uv) {
258 		printf("testing \"rw\"\n");
259 		if (unveil(uv_file1, "rw") == -1)
260 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
261 		if (unveil("/", "") == -1)
262 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
263 	}
264 	UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open");
265 	UV_SHOULD_SUCCEED((open(uv_file1, O_RDONLY) == -1), "open");
266 	return 0;
267 }
268 
269 static int
270 test_x(int do_uv)
271 {
272 	struct stat sb;
273 	if (do_uv) {
274 		printf("testing \"x\"\n");
275 		if (unveil(uv_file1, "x") == -1)
276 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
277 		if (unveil("/", "") == -1)
278 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
279 	}
280 	UV_SHOULD_EACCES((lstat(uv_file1, &sb) == -1), "lstat");
281 	UV_SHOULD_EACCES((open(uv_file1, O_RDONLY) == -1), "open");
282 	UV_SHOULD_EACCES((open(uv_file1, O_RDONLY) == -1), "open");
283 	UV_SHOULD_ENOENT((open(uv_file2, O_RDWR) == -1), "open");
284 	return 0;
285 }
286 
287 static int
288 test_noflags(int do_uv)
289 {
290 	char filename[256];
291 
292 	if (do_uv) {
293 		printf("testing clearing flags\n");
294 		do_unveil();
295 	}
296 
297 	UV_SHOULD_SUCCEED((pledge("unveil stdio rpath cpath wpath exec", NULL) == -1), "pledge");
298 	UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open");
299 	if (do_uv) {
300 		if (unveil(uv_dir1, "") == -1)
301 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
302 	}
303 	(void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir1, "noflagsiamboned");
304 	UV_SHOULD_ENOENT((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open");
305 	UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open");
306 	return 0;
307 }
308 
309 
310 static int
311 test_drounveil(int do_uv)
312 {
313 	if (do_uv) {
314 		printf("(testing unveil after pledge)\n");
315 		do_unveil();
316 	}
317 
318 	UV_SHOULD_SUCCEED((pledge("unveil stdio rpath cpath wpath exec", NULL) == -1), "pledge");
319 
320 	if (do_uv) {
321 		do_unveil();
322 	}
323 	UV_SHOULD_SUCCEED((pledge("stdio rpath cpath wpath", NULL) == -1), "pledge");
324 
325 	UV_SHOULD_ENOENT((open(uv_file2, O_RDWR) == -1), "open");
326 	UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open");
327 	return 0;
328 }
329 
330 static int
331 test_unlink(int do_uv)
332 {
333 	char filename1[256];
334 	char filename2[256];
335 	char filename3[] = "/tmp/nukeme.XXXXXX";
336 	int fd;
337 
338 	(void) snprintf(filename1, sizeof(filename1), "%s/%s", uv_dir1,
339 	    "nukeme");
340 	(void) snprintf(filename2, sizeof(filename2), "%s/%s", uv_dir2,
341 	    "nukeme");
342 	UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open");
343 	UV_SHOULD_SUCCEED((open(filename2, O_RDWR|O_CREAT, 0644) == -1), "open");
344 	if ((fd = mkstemp(filename3)) == -1)
345 		err(1, "%s:%d - mkstemp", __FILE__, __LINE__);
346 	if (do_uv) {
347 		printf("testing unlink\n");
348 		do_unveil();
349 		if (unveil(filename3, "rw") == -1)
350 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
351 	}
352 
353 	UV_SHOULD_SUCCEED((pledge("unveil stdio fattr rpath cpath wpath", NULL) == -1),
354 	    "pledge");
355 	UV_SHOULD_SUCCEED((unlink(filename1) == -1), "unlink");
356 	UV_SHOULD_ENOENT((unlink(filename2) == -1), "unlink");
357 	UV_SHOULD_EACCES((unlink(filename3) == -1), "unlink");
358 	return 0;
359 }
360 
361 static int
362 test_link(int do_uv)
363 {
364 	char filename[256];
365 	char filename2[256];
366 
367 	if (do_uv) {
368 		printf("testing link\n");
369 		do_unveil();
370 	}
371 
372 	UV_SHOULD_SUCCEED((pledge("unveil stdio fattr rpath cpath wpath", NULL) == -1),
373 	    "pledge");
374 	(void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir1,
375 	    "linkuv1");
376 	(void) snprintf(filename2, sizeof(filename2), "%s/%s", uv_dir2,
377 	    "linkuv2");
378 	unlink(filename);
379 	unlink(filename2);
380 	UV_SHOULD_SUCCEED((link(uv_file1, filename) == -1), "link");
381 	unlink(filename);
382 	UV_SHOULD_ENOENT((link(uv_file2, filename) == -1), "link");
383 	UV_SHOULD_ENOENT((link(uv_file1, filename2) == -1), "link");
384 	if (do_uv) {
385 		printf("testing link without O_CREAT\n");
386 		if (unveil(filename, "rw") == -1)
387 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
388 
389 	}
390 	UV_SHOULD_EACCES((link(uv_file1, filename) == -1), "link");
391 	unlink(filename);
392 
393 	return 0;
394 }
395 
396 
397 static int
398 test_chdir(int do_uv)
399 {
400 	if (do_uv) {
401 		printf("testing chdir\n");
402 		do_unveil2();
403 	}
404 
405 	UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
406 	UV_SHOULD_ENOENT((chdir(uv_dir2) == -1), "chdir");
407 	UV_SHOULD_SUCCEED((chdir(uv_dir1) == -1), "chdir");
408 	UV_SHOULD_ENOENT((chdir(uv_dir2) == -1), "chdir");
409 
410 	return 0;
411 }
412 
413 static int
414 test_parent_dir(int do_uv)
415 {
416 	char filename[255];
417 	if (do_uv) {
418 		printf("testing parent dir\n");
419 		do_unveil2();
420 	} else {
421 		(void) snprintf(filename, sizeof(filename), "/%s/doof", uv_dir1);
422 		UV_SHOULD_SUCCEED((mkdir(filename, 0777) == -1), "mkdir");
423 		(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir2", uv_dir1);
424 		UV_SHOULD_SUCCEED((mkdir(filename, 0777) == -1), "mkdir");
425 		(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1", uv_dir1);
426 		UV_SHOULD_SUCCEED((mkdir(filename, 0777) == -1), "mkdir");
427 		(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1/poop", uv_dir1);
428 		UV_SHOULD_SUCCEED((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open");
429 		(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1/link", uv_dir1);
430 		UV_SHOULD_SUCCEED((symlink("../subdir1/poop", filename) == -1), "symlink");
431 	}
432 	sleep(1);
433 	(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1/link", uv_dir1);
434 	UV_SHOULD_SUCCEED((access(filename, R_OK) == -1), "access");
435 	(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1/poop", uv_dir1);
436 	UV_SHOULD_SUCCEED((access(filename, R_OK) == -1), "access");
437 	UV_SHOULD_SUCCEED((chdir(uv_dir1) == -1), "chdir");
438 	(void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1", uv_dir1);
439 	UV_SHOULD_SUCCEED((chdir(filename) == -1), "chdir");
440 	UV_SHOULD_SUCCEED((access("poop", R_OK) == -1), "access");
441 	UV_SHOULD_SUCCEED((chdir("../subdir2") == -1), "chdir");
442 	UV_SHOULD_SUCCEED((chdir("../subdir1") == -1), "chdir");
443 	UV_SHOULD_SUCCEED((chdir(filename) == -1), "chdir");
444 	UV_SHOULD_SUCCEED((chdir("../../doof/subdir2") == -1), "chdir");
445 	UV_SHOULD_SUCCEED((chdir("../../doof/subdir1") == -1), "chdir");
446 	UV_SHOULD_SUCCEED((chdir("../../doof/subdir2") == -1), "chdir");
447 	UV_SHOULD_SUCCEED((chdir("../../doof/subdir1") == -1), "chdir");
448 	UV_SHOULD_SUCCEED((access("poop", R_OK) == -1), "access");
449 	UV_SHOULD_SUCCEED((access("../subdir1/poop", R_OK) == -1), "access");
450 	UV_SHOULD_ENOENT((chdir("../../..") == -1), "chdir");
451 	UV_SHOULD_ENOENT((chdir(uv_dir2) == -1), "chdir");
452 	return(0);
453 }
454 
455 static int
456 test_rename(int do_uv)
457 {
458 	char filename1[256];
459 	char filename2[256];
460 	char rfilename1[256];
461 	char rfilename2[256];
462 	int dirfd1, dirfd2;
463 
464 	if ((dirfd1 = open(uv_dir1, O_RDONLY | O_DIRECTORY)) == -1)
465 		err(1, "%s:%d - open of dir1", __FILE__, __LINE__);
466 	if ((dirfd2 = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1)
467 		err(1, "%s:%d - open of dir2", __FILE__, __LINE__);
468 	(void) snprintf(filename1, sizeof(filename1), "%s/%s", uv_dir1,
469 	    "file1");
470 	UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open");
471 	(void) snprintf(filename2, sizeof(filename2), "%s/%s", uv_dir2,
472 	    "file2");
473         UV_SHOULD_SUCCEED((open(filename2, O_RDWR|O_CREAT, 0644) == -1), "open");
474 	(void) snprintf(rfilename1, sizeof(rfilename1), "%s/%s", uv_dir1,
475 	    "rfile1");
476 	(void) snprintf(rfilename2, sizeof(rfilename2), "%s/%s", uv_dir2,
477 	    "rfile2");
478 	if (do_uv) {
479 		printf("testing rename\n");
480 		do_unveil();
481 	}
482 
483 	UV_SHOULD_SUCCEED((pledge("stdio fattr rpath wpath cpath", NULL) == -1),
484 	    "pledge");
485 	UV_SHOULD_SUCCEED((rename(filename1, rfilename1) == -1), "rename");
486 	UV_SHOULD_ENOENT((rename(filename2, rfilename2) == -1), "rename");
487 	UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open");
488 	UV_SHOULD_ENOENT((rename(filename1, rfilename2) == -1), "rename");
489 	UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open");
490 	UV_SHOULD_ENOENT((rename(filename1, uv_file2) == -1), "rename");
491 	UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open");
492 	UV_SHOULD_ENOENT((renameat(dirfd1, "file1", dirfd2, "rfile2") == -1),
493 	    "renameat");
494 	UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open");
495 	UV_SHOULD_ENOENT((renameat(dirfd1, "file1", dirfd2, rfilename2) == -1),
496 	    "renameat");
497 
498 	return (0);
499 }
500 
501 
502 static int
503 test_access(int do_uv)
504 {
505 	if (do_uv) {
506 		printf("testing access\n");
507 		do_unveil();
508 	}
509 
510 	UV_SHOULD_SUCCEED((access(uv_file1, R_OK) == -1), "access");
511 	UV_SHOULD_ENOENT((access(uv_file2, R_OK) == -1), "access");
512 	UV_SHOULD_ENOENT((access("/etc/passwd", R_OK) == -1), "access");
513 	UV_SHOULD_SUCCEED((access(uv_dir1, R_OK) == -1), "access");
514 	UV_SHOULD_ENOENT((access(uv_dir2, R_OK) == -1), "access");
515 	UV_SHOULD_ENOENT((access("/", R_OK) == -1), "access");
516 	UV_SHOULD_ENOENT((access("/home", F_OK) == -1), "access");
517 
518 	UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
519 	UV_SHOULD_SUCCEED((access(uv_file1, R_OK) == -1), "access");
520 	UV_SHOULD_ENOENT((access(uv_file2, R_OK) == -1), "access");
521 	UV_SHOULD_SUCCEED((access(uv_dir1, R_OK) == -1), "access");
522 	UV_SHOULD_ENOENT((access(uv_dir2, R_OK) == -1), "access");
523 	UV_SHOULD_ENOENT((access("/", R_OK) == -1), "access");
524 	UV_SHOULD_ENOENT((access("/home", F_OK) == -1), "access");
525 
526 	return 0;
527 }
528 
529 static int
530 test_chflags(int do_uv)
531 {
532 	if (do_uv) {
533 		printf("testing chflags\n");
534 		do_unveil();
535 	}
536 
537 	UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
538 	UV_SHOULD_SUCCEED((chflags(uv_file1, UF_NODUMP) == -1), "chflags");
539 	UV_SHOULD_ENOENT((chflags(uv_file2, UF_NODUMP) == -1), "chflags");
540 
541 	return 0;
542 }
543 
544 static int
545 test_stat(int do_uv)
546 {
547 	if (do_uv) {
548 		printf("testing stat\n");
549 		do_unveil();
550 	}
551 	struct stat sb;
552 
553 	UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
554 	UV_SHOULD_SUCCEED((stat(uv_file1, &sb) == -1), "stat");
555 	UV_SHOULD_ENOENT((stat(uv_file2, &sb) == -1), "stat");
556 	UV_SHOULD_SUCCEED((stat(uv_dir1, &sb) == -1), "stat");
557 	UV_SHOULD_ENOENT((stat(uv_dir2, &sb) == -1), "stat");
558 	UV_SHOULD_ENOENT((stat("/", &sb) == -1), "stat");
559 
560 	return 0;
561 }
562 
563 static int
564 test_stat2(int do_uv)
565 {
566 	if (do_uv) {
567 		printf("testing stat components to nonexistent \"rw\"\n");
568 		if (unveil("/usr/share/man/nonexistent", "rw") == -1)
569 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
570 	}
571 	struct stat sb;
572 
573 	UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
574 	UV_SHOULD_ENOENT((stat("/", &sb) == -1), "stat");
575 	UV_SHOULD_ENOENT((stat("/usr", &sb) == -1), "stat");
576 	UV_SHOULD_ENOENT((stat("/usr/share", &sb) == -1), "stat");
577 	UV_SHOULD_ENOENT((stat("/usr/share/man", &sb) == -1), "stat");
578 	UV_SHOULD_ENOENT((stat("/usr/share/man/nonexistent", &sb) == -1), "stat");
579 	return 0;
580 }
581 
582 static int
583 test_statfs(int do_uv)
584 {
585 	if (do_uv) {
586 		printf("testing statfs\n");
587 		do_unveil();
588 	}
589 	struct statfs sb;
590 
591 
592 	UV_SHOULD_SUCCEED((statfs("/home", &sb) == -1), "statfs");
593 	UV_SHOULD_SUCCEED((statfs("/", &sb) == -1), "statfs");
594 	UV_SHOULD_SUCCEED((statfs(uv_file1, &sb) == -1), "statfs");
595 	UV_SHOULD_SUCCEED((statfs(uv_file2, &sb) == -1), "statfs");
596 	UV_SHOULD_SUCCEED((statfs(uv_dir1, &sb) == -1), "statfs");
597 	UV_SHOULD_SUCCEED((statfs(uv_dir2, &sb) == -1), "statfs");
598 	UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
599 	UV_SHOULD_SUCCEED((statfs(uv_file1, &sb) == -1), "statfs");
600 	UV_SHOULD_SUCCEED((statfs(uv_file2, &sb) == -1), "statfs");
601 	UV_SHOULD_SUCCEED((statfs(uv_dir1, &sb) == -1), "statfs");
602 	UV_SHOULD_SUCCEED((statfs(uv_dir2, &sb) == -1), "statfs");
603 
604 	return 0;
605 }
606 
607 static int
608 test_symlink(int do_uv)
609 {
610 	char filename[256];
611 	char filename2[256];
612 	char buf[256];
613 	struct stat sb;
614 
615 	if (do_uv) {
616 		printf("testing symlink and lstat and readlink\n");
617 		do_unveil();
618 	}
619 
620 	UV_SHOULD_SUCCEED((pledge("unveil stdio fattr rpath cpath wpath", NULL) == -1),
621 	    "pledge");
622 	(void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir1,
623 	    "slinkuv1");
624 	(void) snprintf(filename2, sizeof(filename2), "%s/%s", uv_dir2,
625 	    "slinkuv2");
626 	unlink(filename);
627 	unlink(filename2);
628 	UV_SHOULD_SUCCEED((symlink(uv_file1, filename) == -1), "symlink");
629 	UV_SHOULD_SUCCEED((lstat(filename, &sb) == -1), "lstat");
630 	UV_SHOULD_SUCCEED((lstat(uv_file1, &sb) == -1), "lstat");
631 	UV_SHOULD_SUCCEED((readlink(filename, buf, sizeof(buf)) == -1), "readlink");
632 	unlink(filename);
633 	UV_SHOULD_SUCCEED((symlink(uv_file2, filename) == -1), "symlink");
634 	UV_SHOULD_SUCCEED((lstat(filename, &sb) == -1), "lstat");
635 	UV_SHOULD_SUCCEED((readlink(filename, buf, sizeof(buf)) == -1), "readlink");
636 	UV_SHOULD_ENOENT((lstat(uv_file2, &sb) == -1), "lstat");
637 	UV_SHOULD_ENOENT((symlink(uv_file1, filename2) == -1), "symlink");
638 	UV_SHOULD_ENOENT((readlink(filename2, buf, sizeof(buf)) == -1), "readlink");
639 	unlink(filename);
640 
641 	if (do_uv) {
642 		printf("testing symlink with \"rw\"\n");
643 		if (unveil(filename, "rw") == -1)
644 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
645 	}
646 	UV_SHOULD_EACCES((symlink(uv_file1, filename) == -1), "symlink");
647 
648 	return 0;
649 }
650 
651 static int
652 test_chmod(int do_uv)
653 {
654 	if (do_uv) {
655 		printf("testing chmod\n");
656 		do_unveil();
657 	}
658 	UV_SHOULD_SUCCEED((pledge("stdio fattr rpath unveil", NULL) == -1), "pledge");
659 	UV_SHOULD_SUCCEED((chmod(uv_file1, S_IRWXU) == -1), "chmod");
660 	UV_SHOULD_ENOENT((chmod(uv_file2, S_IRWXU) == -1), "chmod");
661 	UV_SHOULD_SUCCEED((chmod(uv_dir1, S_IRWXU) == -1), "chmod");
662 	UV_SHOULD_ENOENT((chmod(uv_dir2, S_IRWXU) == -1), "chmod");
663 	if (do_uv) {
664 		printf("testing chmod should fail for read\n");
665 		if (unveil(uv_file1, "r") == -1)
666 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
667 	}
668 	UV_SHOULD_EACCES((chmod(uv_file1, S_IRWXU) == -1), "chmod");
669 	return 0;
670 }
671 
672 
673 static int
674 test_fork_body(int do_uv)
675 {
676 	UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR|O_CREAT, 0644) == -1), "open after fork");
677 	UV_SHOULD_SUCCEED((opendir(uv_dir1) == NULL), "opendir after fork");
678 	UV_SHOULD_ENOENT((opendir(uv_dir2) == NULL), "opendir after fork");
679 	UV_SHOULD_ENOENT((open(uv_file2, O_RDWR|O_CREAT, 0644) == -1), "open after fork");
680 	return 0;
681 }
682 
683 static int
684 test_fork(int do_uv)
685 {
686 	printf("testing fork inhertiance\n");
687 	do_unveil();
688 	return runcompare_internal(test_fork_body, 0);
689 }
690 
691 static int
692 test_exec(int do_uv)
693 {
694 	char *argv[] = {"/usr/bin/true", NULL};
695 	extern char **environ;
696 	if (do_uv) {
697 		printf("testing execve with \"x\"\n");
698 		if (unveil("/usr/bin/true", "x") == -1)
699 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
700 		/* dynamic linking requires this */
701 		if (unveil("/usr/lib", "r") == -1)
702 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
703 		if (unveil("/usr/libexec/ld.so", "r") == -1)
704 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
705 	}
706 	UV_SHOULD_SUCCEED((pledge("unveil stdio fattr exec", NULL) == -1), "pledge");
707 	UV_SHOULD_SUCCEED((execve(argv[0], argv, environ) == -1), "execve");
708 	return 0;
709 }
710 
711 static int
712 test_exec2(int do_uv)
713 {
714 	char *argv[] = {"/usr/bin/true", NULL};
715 	extern char **environ;
716 	if (do_uv) {
717 		printf("testing execve with \"rw\"\n");
718 		if (unveil("/usr/bin/true", "rw") == -1)
719 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
720 		/* dynamic linking requires this */
721 		if (unveil("/usr/lib", "r") == -1)
722 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
723 		if (unveil("/usr/libexec/ld.so", "r") == -1)
724 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
725 	}
726 	UV_SHOULD_SUCCEED((pledge("unveil stdio fattr exec", NULL) == -1), "pledge");
727 	UV_SHOULD_EACCES((execve(argv[0], argv, environ) == -1), "execve");
728 	return 0;
729 }
730 
731 static int
732 test_slash(int do_uv)
733 {
734 	extern char **environ;
735 	if (do_uv) {
736 		printf("testing unveil(\"/\")\n");
737 		if (unveil("/bin/sh", "x") == -1)
738 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
739 		if (unveil("/", "r") == -1)
740 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
741 	}
742 	return 0;
743 }
744 
745 static int
746 test_dot(int do_uv)
747 {
748 	extern char **environ;
749 	if (do_uv) {
750 		printf("testing dot(\".\")\n");
751 		if (unveil(".", "rwxc") == -1)
752 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
753 		if ((unlink(".") == -1) && errno != EPERM)
754 			err(1, "%s:%d - unlink", __FILE__, __LINE__);
755 		printf("testing dot flags(\".\")\n");
756 		if (unveil(".", "r") == -1)
757 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
758 		if ((unlink(".") == -1) && errno != EACCES)
759 			warn("%s:%d - unlink", __FILE__, __LINE__);
760 	}
761 	return 0;
762 }
763 
764 static int
765 test_bypassunveil(int do_uv)
766 {
767 	if (do_uv) {
768 		printf("testing BYPASSUNVEIL\n");
769 		do_unveil2();
770 	}
771 	char filename3[] = "/tmp/nukeme.XXXXXX";
772 
773 	UV_SHOULD_SUCCEED((pledge("stdio tmppath", NULL) == -1), "pledge");
774 	UV_SHOULD_SUCCEED((mkstemp(filename3) == -1), "mkstemp");
775 
776 	return 0;
777 }
778 
779 
780 static int
781 test_dotdotup(int do_uv)
782 {
783 	UV_SHOULD_SUCCEED((open("/tmp/hello", O_RDWR|O_CREAT, 0644) == -1), "open");
784 	if (do_uv) {
785 		printf("testing dotdotup\n");
786 		do_unveil2();
787 	}
788 	if ((chdir(uv_dir1) == -1)) {
789 		err(1, "chdir");
790 	}
791 	UV_SHOULD_SUCCEED((open("./derp", O_RDWR|O_CREAT, 0644) == -1), "open");
792 	UV_SHOULD_SUCCEED((open("derp", O_RDWR|O_CREAT, 0644) == -1), "open");
793 	UV_SHOULD_ENOENT((open("../hello", O_RDWR|O_CREAT, 0644) == -1), "open");
794 	UV_SHOULD_ENOENT((open(".././hello", O_RDWR|O_CREAT, 0644) == -1), "open");
795 	return 0;
796 }
797 
798 static int
799 test_kn(int do_uv)
800 {
801 	if (do_uv) {
802 		printf("testing read only with one writeable file\n");
803 		if (unveil("/", "r") == -1)
804 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
805 		if (unveil("/dev/null", "rw") == -1)
806 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
807 	}
808 	UV_SHOULD_SUCCEED((open("/dev/null", O_RDWR) == -1), "open");
809 	UV_SHOULD_SUCCEED((open("/dev/zero", O_RDONLY) == -1), "open");
810 	UV_SHOULD_EACCES((open("/dev/zero", O_RDWR) == -1), "open");
811 	return 0;
812 }
813 
814 
815 static int
816 test_pathdiscover(int do_uv)
817 {
818 	struct stat sb;
819 	if (do_uv) {
820 		printf("testing path discovery\n");
821 		if (unveil("/usr/share/man", "rx") == -1)
822 			err(1, "%s:%d - unveil", __FILE__, __LINE__);
823 	}
824 	UV_SHOULD_SUCCEED((lstat("/usr/share/man", &sb) == -1), "lstat");
825 	UV_SHOULD_SUCCEED((lstat("/usr/share/man/../../share/man", &sb) == -1), "lstat");
826 	/* XXX XXX XXX This should fail */
827 	UV_SHOULD_SUCCEED((lstat("/usr/share/man/../../local/../share/man", &sb) == -1), "lstat");
828 	return 0;
829 }
830 
831 static int
832 test_fchdir(int do_uv)
833 {
834 	int fd2, fd;
835 
836 	UV_SHOULD_SUCCEED(((fd2 = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open");
837 
838 	if (do_uv) {
839 		printf("testing fchdir\n");
840 		do_unveil2();
841 	}
842 
843 	UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge");
844 	UV_SHOULD_SUCCEED((chdir(uv_dir1) == -1), "chdir");
845 	UV_SHOULD_SUCCEED((fchdir(fd2) == -1), "fchdir");
846 	UV_SHOULD_ENOENT((fd = (open("subdir", O_RDONLY | O_DIRECTORY)) == -1), "open");
847 
848 	return 0;
849 }
850 
851 static int
852 test_fork_locked(int do_uv)
853 {
854 	int status;
855 	pid_t pid;
856 
857 	if (do_uv) {
858 		printf("testing unveil locked fork\n");
859 		unveil(NULL, NULL);
860 	}
861 
862 	pid = fork();
863 	if (pid == 0) {
864 		UV_SHOULD_EPERM((unveil("/", "rwx") == -1), "unveil");
865 		exit(0);
866 	}
867 
868 	status = 0;
869 	waitpid(pid, &status, 0);
870 	if (WIFSIGNALED(status))
871 		errx(1, "child exited with signal %d", WTERMSIG(status));
872 	if (WEXITSTATUS(status) == 0)
873 		return 0;
874 	else
875 		return 1;
876 }
877 
878 static int
879 test_intermediate_node(int do_uv)
880 {
881 	struct stat st;
882 
883 	if (do_uv) {
884 		printf("testing unveil on intermediate node\n");
885 		UV_SHOULD_SUCCEED((unveil("/", "r") == -1), "unveil");
886 		UV_SHOULD_SUCCEED((unveil("/usr/bin/id", "rx") == -1),
887 		    "unveil");
888 		UV_SHOULD_SUCCEED((unveil(NULL, NULL) == -1), "unveil");
889 	}
890 
891 	UV_SHOULD_SUCCEED((stat("/usr/bin", &st) == -1), "stat");
892 	return 0;
893 }
894 
895 static int
896 test_noaccess_node(int do_uv)
897 {
898 	struct stat st;
899 
900 	if (do_uv) {
901 		printf("testing unveil on noaccess node\n");
902 		UV_SHOULD_SUCCEED((unveil("/", "r") == -1), "unveil");
903 		UV_SHOULD_SUCCEED((unveil("/usr/bin/id", "rx") == -1),
904 		    "unveil");
905 		UV_SHOULD_SUCCEED((unveil("/usr/bin", "") == -1), "unveil");
906 		UV_SHOULD_SUCCEED((unveil(NULL, NULL) == -1), "unveil");
907 	}
908 
909 	UV_SHOULD_ENOENT((stat("/usr/bin", &st) == -1), "stat");
910 	return 0;
911 }
912 
913 int
914 main(int argc, char *argv[])
915 {
916 	int failures = 0;
917 
918 	test_setup();
919 
920 	failures += runcompare(test_open);
921 	failures += runcompare(test_openat);
922 	failures += runcompare(test_opendir);
923 	failures += runcompare(test_noflags);
924 	failures += runcompare(test_drounveil);
925 	failures += runcompare(test_r);
926 	failures += runcompare(test_rw);
927 	failures += runcompare(test_x);
928 	failures += runcompare(test_unlink);
929 	failures += runcompare(test_link);
930 	failures += runcompare(test_chdir);
931 	failures += runcompare(test_rename);
932 	failures += runcompare(test_access);
933 	failures += runcompare(test_chflags);
934 	failures += runcompare(test_stat);
935 	failures += runcompare(test_stat2);
936 	failures += runcompare(test_statfs);
937 	failures += runcompare(test_symlink);
938 	failures += runcompare(test_chmod);
939 	failures += runcompare(test_exec);
940 	failures += runcompare(test_exec2);
941 	failures += runcompare(test_realpath);
942 	failures += runcompare(test_parent_dir);
943 	failures += runcompare(test_slash);
944 	failures += runcompare(test_dot);
945 	failures += runcompare(test_bypassunveil);
946 	failures += runcompare_internal(test_fork, 0);
947 	failures += runcompare(test_dotdotup);
948 	failures += runcompare(test_kn);
949 	failures += runcompare(test_pathdiscover);
950 	failures += runcompare(test_fchdir);
951 	failures += runcompare(test_fork_locked);
952 	failures += runcompare(test_intermediate_node);
953 	failures += runcompare(test_noaccess_node);
954 	exit(failures);
955 }
956