xref: /freebsd/tools/regression/priv/main.c (revision 2e3507c25e42292b45a5482e116d278f5515d04d)
1 /*-
2  * Copyright (c) 2006 nCircle Network Security, Inc.
3  * Copyright (c) 2007 Robert N. M. Watson
4  * All rights reserved.
5  *
6  * This software was developed by Robert N. M. Watson for the TrustedBSD
7  * Project under contract to nCircle Network Security, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
22  * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /*
32  * Privilege test framework.  Each test is encapsulated on a .c file
33  * exporting a function that implements the test.  Each test is run from its
34  * own child process, and they are run in sequence one at a time.
35  */
36 
37 #include <sys/param.h>
38 #include <sys/jail.h>
39 #include <sys/stat.h>
40 #include <sys/wait.h>
41 
42 #include <netinet/in.h>
43 
44 #include <err.h>
45 #include <errno.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 
51 #include "main.h"
52 
53 /*
54  * If true, some test or preparatory step failed along the execution of this
55  * program.
56  *
57  * Intuitively, we would define a counter instead of a boolean.  However,
58  * we fork to run the subtests and keeping proper track of the number of
59  * failed tests would be tricky and not provide any real value.
60  */
61 static int something_failed = 0;
62 
63 /*
64  * Registration table of privilege tests.  Each test registers a name, a test
65  * function, and a cleanup function to run after the test has completed,
66  * regardless of success/failure.
67  */
68 static struct test tests[] = {
69 	{ "priv_acct_enable", priv_acct_setup, priv_acct_enable,
70 	    priv_acct_cleanup },
71 
72 	{ "priv_acct_disable", priv_acct_setup, priv_acct_disable,
73 	    priv_acct_cleanup },
74 
75 	{ "priv_acct_rotate", priv_acct_setup, priv_acct_rotate,
76 	    priv_acct_cleanup },
77 
78 	{ "priv_acct_noopdisable", priv_acct_setup, priv_acct_noopdisable,
79 	    priv_acct_cleanup },
80 
81 	{ "priv_adjtime_set", priv_adjtime_setup, priv_adjtime_set,
82 	    priv_adjtime_cleanup },
83 
84 	{ "priv_audit_submit", priv_audit_submit_setup, priv_audit_submit,
85 	    priv_audit_submit_cleanup },
86 
87 	{ "priv_audit_control", priv_audit_control_setup, priv_audit_control,
88 	    priv_audit_control_cleanup },
89 
90 	{ "priv_audit_getaudit", priv_audit_getaudit_setup,
91 	    priv_audit_getaudit, priv_audit_getaudit_cleanup },
92 
93 	{ "priv_audit_getaudit_addr", priv_audit_getaudit_setup,
94 	    priv_audit_getaudit_addr, priv_audit_getaudit_cleanup },
95 
96 	{ "priv_audit_setaudit", priv_audit_setaudit_setup,
97 	    priv_audit_setaudit, priv_audit_setaudit_cleanup },
98 
99 	{ "priv_audit_setaudit_addr", priv_audit_setaudit_setup,
100 	    priv_audit_setaudit_addr, priv_audit_setaudit_cleanup },
101 
102 	{ "priv_clock_settime", priv_clock_settime_setup, priv_clock_settime,
103 	    priv_clock_settime_cleanup },
104 
105 	{ "priv_cred_setuid", priv_cred_setup, priv_cred_setuid,
106 	    priv_cred_cleanup },
107 
108 	{ "priv_cred_seteuid", priv_cred_setup, priv_cred_seteuid,
109 	    priv_cred_cleanup },
110 
111 	{ "priv_cred_setgid", priv_cred_setup, priv_cred_setgid,
112 	    priv_cred_cleanup },
113 
114 	{ "priv_cred_setegid", priv_cred_setup, priv_cred_setegid,
115 	    priv_cred_cleanup },
116 
117 	{ "priv_cred_setgroups", priv_cred_setup, priv_cred_setgroups,
118 	    priv_cred_cleanup },
119 
120 	{ "priv_cred_setreuid", priv_cred_setup, priv_cred_setreuid,
121 	    priv_cred_cleanup },
122 
123 	{ "priv_cred_setregid", priv_cred_setup, priv_cred_setregid,
124 	    priv_cred_cleanup },
125 
126 	{ "priv_cred_setresuid", priv_cred_setup, priv_cred_setresuid,
127 	    priv_cred_cleanup },
128 
129 	{ "priv_cred_setresgid", priv_cred_setup, priv_cred_setresgid,
130 	    priv_cred_cleanup },
131 
132 	{ "priv_io", priv_io_setup, priv_io, priv_io_cleanup },
133 
134 	{ "priv_kenv_set", priv_kenv_set_setup, priv_kenv_set,
135 	    priv_kenv_set_cleanup },
136 
137 	{ "priv_kenv_unset", priv_kenv_unset_setup, priv_kenv_unset,
138 	    priv_kenv_unset_cleanup },
139 
140 	{ "priv_msgbuf_privonly", priv_msgbuf_privonly_setup,
141 	    priv_msgbuf_privonly, priv_msgbuf_cleanup },
142 
143 	{ "priv_msgbuf_unprivok", priv_msgbuf_unprivok_setup,
144 	   priv_msgbuf_unprivok, priv_msgbuf_cleanup },
145 
146 	{ "priv_netinet_ipsec_pfkey", NULL, priv_netinet_ipsec_pfkey, NULL },
147 
148 	{ "priv_netinet_ipsec_policy4_bypass",
149 	    priv_netinet_ipsec_policy4_bypass_setup,
150 	    priv_netinet_ipsec_policy4_bypass,
151 	    priv_netinet_ipsec_policy_bypass_cleanup },
152 
153 #ifdef INET6
154 	{ "priv_netinet_ipsec_policy6_bypass",
155 	    priv_netinet_ipsec_policy6_bypass_setup,
156 	    priv_netinet_ipsec_policy6_bypass,
157 	    priv_netinet_ipsec_policy_bypass_cleanup },
158 #endif
159 
160 	{ "priv_netinet_ipsec_policy4_entrust",
161 	    priv_netinet_ipsec_policy4_entrust_setup,
162 	    priv_netinet_ipsec_policy4_entrust,
163 	    priv_netinet_ipsec_policy_entrust_cleanup },
164 
165 #ifdef INET6
166 	{ "priv_netinet_ipsec_policy6_entrust",
167 	    priv_netinet_ipsec_policy6_entrust_setup,
168 	    priv_netinet_ipsec_policy6_entrust,
169 	    priv_netinet_ipsec_policy_entrust_cleanup },
170 #endif
171 
172 	{ "priv_netinet_raw", priv_netinet_raw_setup, priv_netinet_raw,
173 	    priv_netinet_raw_cleanup },
174 
175 	{ "priv_proc_setlogin", priv_proc_setlogin_setup, priv_proc_setlogin,
176 	    priv_proc_setlogin_cleanup },
177 
178 	{ "priv_proc_setrlimit_raisemax", priv_proc_setrlimit_setup,
179 	    priv_proc_setrlimit_raisemax, priv_proc_setrlimit_cleanup },
180 
181 	{ "priv_proc_setrlimit_raisecur", priv_proc_setrlimit_setup,
182 	    priv_proc_setrlimit_raisecur, priv_proc_setrlimit_cleanup },
183 
184 	{ "priv_proc_setrlimit_raisecur_nopriv", priv_proc_setrlimit_setup,
185 	    priv_proc_setrlimit_raisecur_nopriv,
186 	    priv_proc_setrlimit_cleanup },
187 
188 	{ "priv_sched_rtprio_curproc_normal", priv_sched_rtprio_setup,
189 	    priv_sched_rtprio_curproc_normal, priv_sched_rtprio_cleanup },
190 
191 	{ "priv_sched_rtprio_curproc_idle", priv_sched_rtprio_setup,
192 	    priv_sched_rtprio_curproc_idle, priv_sched_rtprio_cleanup },
193 
194 	{ "priv_sched_rtprio_curproc_realtime", priv_sched_rtprio_setup,
195 	    priv_sched_rtprio_curproc_realtime, priv_sched_rtprio_cleanup },
196 
197 	{ "priv_sched_rtprio_myproc_normal", priv_sched_rtprio_setup,
198 	    priv_sched_rtprio_myproc_normal, priv_sched_rtprio_cleanup },
199 
200 	{ "priv_sched_rtprio_myproc_idle", priv_sched_rtprio_setup,
201 	    priv_sched_rtprio_myproc_idle, priv_sched_rtprio_cleanup },
202 
203 	{ "priv_sched_rtprio_myproc_realtime", priv_sched_rtprio_setup,
204 	    priv_sched_rtprio_myproc_realtime, priv_sched_rtprio_cleanup },
205 
206 	{ "priv_sched_rtprio_aproc_normal", priv_sched_rtprio_setup,
207 	    priv_sched_rtprio_aproc_normal, priv_sched_rtprio_cleanup },
208 
209 	{ "priv_sched_rtprio_aproc_idle", priv_sched_rtprio_setup,
210 	    priv_sched_rtprio_aproc_idle, priv_sched_rtprio_cleanup },
211 
212 	{ "priv_sched_rtprio_aproc_realtime", priv_sched_rtprio_setup,
213 	    priv_sched_rtprio_aproc_realtime, priv_sched_rtprio_cleanup },
214 
215 	{ "priv_sched_setpriority_curproc", priv_sched_setpriority_setup,
216 	    priv_sched_setpriority_curproc, priv_sched_setpriority_cleanup },
217 
218 	{ "priv_sched_setpriority_myproc", priv_sched_setpriority_setup,
219 	    priv_sched_setpriority_myproc, priv_sched_setpriority_cleanup },
220 
221 	{ "priv_sched_setpriority_aproc", priv_sched_setpriority_setup,
222 	    priv_sched_setpriority_aproc, priv_sched_setpriority_cleanup },
223 
224 	{ "priv_settimeofday", priv_settimeofday_setup, priv_settimeofday,
225 	    priv_settimeofday_cleanup },
226 
227 	{ "priv_sysctl_write", priv_sysctl_write_setup, priv_sysctl_write,
228 	    priv_sysctl_write_cleanup },
229 
230 	{ "priv_sysctl_writejail", priv_sysctl_write_setup,
231 	    priv_sysctl_writejail, priv_sysctl_write_cleanup },
232 
233 	{ "priv_vfs_chflags_froot_uflags", priv_vfs_chflags_froot_setup,
234 	    priv_vfs_chflags_froot_uflags, priv_vfs_chflags_cleanup },
235 
236 	{ "priv_vfs_chflags_froot_sflags", priv_vfs_chflags_froot_setup,
237 	    priv_vfs_chflags_froot_sflags, priv_vfs_chflags_cleanup },
238 
239 	{ "priv_vfs_chflags_fowner_uflags", priv_vfs_chflags_fowner_setup,
240 	    priv_vfs_chflags_fowner_uflags, priv_vfs_chflags_cleanup },
241 
242 	{ "priv_vfs_chflags_fowner_sflags", priv_vfs_chflags_fowner_setup,
243 	    priv_vfs_chflags_fowner_sflags, priv_vfs_chflags_cleanup },
244 
245 	{ "priv_vfs_chflags_fother_uflags", priv_vfs_chflags_fother_setup,
246 	    priv_vfs_chflags_fother_uflags, priv_vfs_chflags_cleanup },
247 
248 	{ "priv_vfs_chflags_fother_sflags", priv_vfs_chflags_fother_setup,
249 	    priv_vfs_chflags_fother_sflags, priv_vfs_chflags_cleanup },
250 
251 	{ "priv_vfs_chmod_froot", priv_vfs_chmod_froot_setup,
252 	     priv_vfs_chmod_froot, priv_vfs_chmod_cleanup },
253 
254 	{ "priv_vfs_chmod_fowner", priv_vfs_chmod_fowner_setup,
255 	     priv_vfs_chmod_fowner, priv_vfs_chmod_cleanup },
256 
257 	{ "priv_vfs_chmod_fother", priv_vfs_chmod_fother_setup,
258 	     priv_vfs_chmod_fother, priv_vfs_chmod_cleanup },
259 
260 	{ "priv_vfs_chown_uid", priv_vfs_chown_uid_setup, priv_vfs_chown_uid,
261 	    priv_vfs_chown_cleanup },
262 
263 	{ "priv_vfs_chown_mygid", priv_vfs_chown_mygid_setup,
264 	    priv_vfs_chown_mygid, priv_vfs_chown_cleanup },
265 
266 	{ "priv_vfs_chown_othergid", priv_vfs_chown_othergid_setup,
267 	    priv_vfs_chown_othergid, priv_vfs_chown_cleanup },
268 
269 	{ "priv_vfs_chroot", priv_vfs_chroot_setup, priv_vfs_chroot,
270 	    priv_vfs_chroot_cleanup },
271 
272 	{ "priv_vfs_clearsugid_chgrp", priv_vfs_clearsugid_setup,
273 	    priv_vfs_clearsugid_chgrp, priv_vfs_clearsugid_cleanup },
274 
275 	{ "priv_vfs_clearsugid_extattr", priv_vfs_clearsugid_setup,
276 	    priv_vfs_clearsugid_extattr, priv_vfs_clearsugid_cleanup },
277 
278 	{ "priv_vfs_clearsugid_write", priv_vfs_clearsugid_setup,
279 	    priv_vfs_clearsugid_write, priv_vfs_clearsugid_cleanup },
280 
281 	{ "priv_vfs_extattr_system", priv_vfs_extattr_system_setup,
282 	    priv_vfs_extattr_system, priv_vfs_extattr_system_cleanup },
283 
284 	{ "priv_vfs_fhopen", priv_vfs_fhopen_setup, priv_vfs_fhopen,
285 	    priv_vfs_fhopen_cleanup },
286 
287 	{ "priv_vfs_fhstat", priv_vfs_fhstat_setup, priv_vfs_fhstat,
288 	    priv_vfs_fhstat_cleanup },
289 
290 	{ "priv_vfs_fhstatfs", priv_vfs_fhstatfs_setup, priv_vfs_fhstatfs,
291 	    priv_vfs_fhstatfs_cleanup },
292 
293 	{ "priv_vfs_generation", priv_vfs_generation_setup,
294 	    priv_vfs_generation, priv_vfs_generation_cleanup },
295 
296 	{ "priv_vfs_getfh", priv_vfs_getfh_setup, priv_vfs_getfh,
297 	    priv_vfs_getfh_cleanup },
298 
299 	{ "priv_vfs_readwrite_fowner", priv_vfs_readwrite_fowner_setup,
300 	    priv_vfs_readwrite_fowner, priv_vfs_readwrite_cleanup },
301 
302 	{ "priv_vfs_readwrite_fgroup", priv_vfs_readwrite_fgroup_setup,
303 	    priv_vfs_readwrite_fgroup, priv_vfs_readwrite_cleanup },
304 
305 	{ "priv_vfs_readwrite_fother", priv_vfs_readwrite_fother_setup,
306 	    priv_vfs_readwrite_fother, priv_vfs_readwrite_cleanup },
307 
308 	{ "priv_vfs_setgid_fowner", priv_vfs_setgid_fowner_setup,
309 	    priv_vfs_setgid_fowner, priv_vfs_setgid_cleanup },
310 
311 	{ "priv_vfs_setgid_fother", priv_vfs_setgid_fother_setup,
312 	    priv_vfs_setgid_fother, priv_vfs_setgid_cleanup },
313 
314 	{ "priv_vfs_stickyfile_dir_fowner",
315 	    priv_vfs_stickyfile_dir_fowner_setup,
316 	    priv_vfs_stickyfile_dir_fowner,
317 	    priv_vfs_stickyfile_dir_cleanup },
318 
319 	{ "priv_vfs_stickyfile_dir_fother",
320 	    priv_vfs_stickyfile_dir_fother_setup,
321 	    priv_vfs_stickyfile_dir_fother,
322 	    priv_vfs_stickyfile_dir_cleanup },
323 
324 	{ "priv_vfs_stickyfile_file_fowner",
325 	    priv_vfs_stickyfile_file_fowner_setup,
326 	    priv_vfs_stickyfile_file_fowner,
327 	    priv_vfs_stickyfile_file_cleanup },
328 
329 	{ "priv_vfs_stickyfile_file_fother",
330 	    priv_vfs_stickyfile_file_fother_setup,
331 	    priv_vfs_stickyfile_file_fother,
332 	    priv_vfs_stickyfile_file_cleanup },
333 
334 	{ "priv_vfs_utimes_froot", priv_vfs_utimes_froot_setup,
335 	    priv_vfs_utimes_froot, priv_vfs_utimes_cleanup },
336 
337 	{ "priv_vfs_utimes_froot_null", priv_vfs_utimes_froot_setup,
338 	    priv_vfs_utimes_froot_null, priv_vfs_utimes_cleanup },
339 
340 	{ "priv_vfs_utimes_fowner", priv_vfs_utimes_fowner_setup,
341 	    priv_vfs_utimes_fowner, priv_vfs_utimes_cleanup },
342 
343 	{ "priv_vfs_utimes_fowner_null", priv_vfs_utimes_fowner_setup,
344 	    priv_vfs_utimes_fowner_null, priv_vfs_utimes_cleanup },
345 
346 	{ "priv_vfs_utimes_fother", priv_vfs_utimes_fother_setup,
347 	    priv_vfs_utimes_fother, priv_vfs_utimes_cleanup },
348 
349 	{ "priv_vfs_utimes_fother_null", priv_vfs_utimes_fother_setup,
350 	    priv_vfs_utimes_fother_null, priv_vfs_utimes_cleanup },
351 
352 	{ "priv_vm_madv_protect", priv_vm_madv_protect_setup,
353 	    priv_vm_madv_protect, priv_vm_madv_protect_cleanup },
354 
355 	{ "priv_vm_mlock", priv_vm_mlock_setup, priv_vm_mlock,
356 	    priv_vm_mlock_cleanup },
357 
358 	{ "priv_vm_munlock", priv_vm_munlock_setup, priv_vm_munlock,
359 	    priv_vm_munlock_cleanup },
360 
361 };
362 static int tests_count = sizeof(tests) / sizeof(struct test);
363 
364 void
365 expect(const char *test, int error, int expected_error, int expected_errno)
366 {
367 
368 	if (error == 0) {
369 		if (expected_error != 0) {
370 			something_failed = 1;
371 			warnx("%s: returned 0", test);
372 		}
373 	} else {
374 		if (expected_error == 0) {
375 			something_failed = 1;
376 			warn("%s: returned (%d, %d)", test, error, errno);
377 		} else if (expected_errno != errno) {
378 			something_failed = 1;
379 			warn("%s: returned (%d, %d)", test, error, errno);
380 		}
381 	}
382 }
383 
384 void
385 setup_dir(const char *test, char *dpathp, uid_t uid, gid_t gid, mode_t mode)
386 {
387 
388 	strcpy(dpathp, "/tmp/priv.XXXXXXXXXXX");
389 	if (mkdtemp(dpathp) == NULL)
390 		err(-1, "test %s: mkdtemp", test);
391 
392 	if (chown(dpathp, uid, gid) < 0)
393 		err(-1, "test %s: chown(%s, %d, %d)", test, dpathp, uid,
394 		    gid);
395 
396 	if (chmod(dpathp, mode) < 0)
397 		err(-1, "test %s: chmod(%s, 0%o)", test, dpathp, mode);
398 }
399 
400 void
401 setup_file(const char *test, char *fpathp, uid_t uid, gid_t gid, mode_t mode)
402 {
403 	int fd;
404 
405 	strcpy(fpathp, "/tmp/priv.XXXXXXXXXXX");
406 	fd = mkstemp(fpathp);
407 	if (fd < 0)
408 		err(-1, "test %s: mkstemp", test);
409 
410 	if (fchown(fd, uid, gid) < 0)
411 		err(-1, "test %s: fchown(%s, %d, %d)", test, fpathp, uid,
412 		    gid);
413 
414 	if (fchmod(fd, mode) < 0)
415 		err(-1, "test %s: chmod(%s, 0%o)", test, fpathp, mode);
416 
417 	close(fd);
418 }
419 
420 /*
421  * Irrevocably set credentials to specific uid and gid.
422  */
423 static void
424 set_creds(const char *test, uid_t uid, gid_t gid)
425 {
426 	gid_t gids[1] = { gid };
427 
428 	if (setgid(gid) < 0)
429 		err(-1, "test %s: setegid(%d)", test, gid);
430 	if (setgroups(sizeof(gids)/sizeof(gid_t), gids) < 0)
431 		err(-1, "test %s: setgroups(%d)", test, gid);
432 	if (setuid(uid) < 0)
433 		err(-1, "test %s: seteuid(%d)", test, uid);
434 }
435 
436 static void
437 enter_jail(const char *test)
438 {
439 	struct jail j;
440 	struct in_addr ia4;
441 #ifdef INET6
442 	struct in6_addr ia6 = IN6ADDR_LOOPBACK_INIT;
443 #endif
444 
445 	bzero(&j, sizeof(j));
446 	j.version = JAIL_API_VERSION;
447 	j.path = "/";
448 	j.hostname = "test";
449 	j.jailname = "regressions/priv";
450 	ia4.s_addr = htonl(INADDR_LOOPBACK);
451 	j.ip4s = 1;
452 	j.ip4 = &ia4;
453 #ifdef INET6
454 	j.ip6s = 1;
455 	j.ip6 = &ia6;
456 #endif
457 	if (jail(&j) < 0)
458 		err(-1, "test %s: jail", test);
459 }
460 
461 static void
462 run_child(struct test *test, int asroot, int injail)
463 {
464 
465 	setprogname(test->t_name);
466 	if (injail)
467 		enter_jail(test->t_name);
468 	if (!asroot)
469 		set_creds(test->t_name, UID_OWNER, GID_OWNER);
470 	test->t_test_func(asroot, injail, test);
471 }
472 
473 /*
474  * Run a test in a particular credential context -- always call the setup and
475  * cleanup routines; if setup succeeds, also run the test.  Test cleanup must
476  * handle cases where the setup has failed, so may need to maintain their own
477  * state in order to know what needs cleaning up (such as whether temporary
478  * files were created).
479  */
480 static void
481 run(struct test *test, int asroot, int injail)
482 {
483 	pid_t childpid, pid;
484 
485 	if (test->t_setup_func != NULL) {
486 		if ((test->t_setup_func)(asroot, injail, test) != 0) {
487 			warnx("run(%s, %d, %d) setup failed", test->t_name,
488 			    asroot, injail);
489 			goto cleanup;
490 		}
491 	}
492 	fflush(stdout);
493 	fflush(stderr);
494 	childpid = fork();
495 	if (childpid == -1) {
496 		warn("run(%s, %d, %d) fork failed", test->t_name, asroot,
497 		    injail);
498 		goto cleanup;
499 	}
500 	if (childpid == 0) {
501 		run_child(test, asroot, injail);
502 		fflush(stdout);
503 		fflush(stderr);
504 		exit(something_failed ? EXIT_FAILURE : EXIT_SUCCESS);
505 	} else {
506 		while (1) {
507 			int status;
508 			pid = waitpid(childpid, &status, 0);
509 			if (pid == -1) {
510 				something_failed = 1;
511 				warn("test: waitpid %s", test->t_name);
512 			}
513 			if (pid == childpid) {
514 				if (WIFEXITED(status) &&
515 				    WEXITSTATUS(status) == EXIT_SUCCESS) {
516 					/* All good in the subprocess! */
517 				} else {
518 					something_failed = 1;
519 				}
520 				break;
521 			}
522 		}
523 	}
524 	fflush(stdout);
525 	fflush(stderr);
526 cleanup:
527 	if (test->t_cleanup_func != NULL)
528 		test->t_cleanup_func(asroot, injail, test);
529 }
530 
531 int
532 main(int argc, char *argv[])
533 {
534 	int i;
535 
536 	/*
537 	 * This test suite will need to become quite a bit more enlightened
538 	 * if the notion of privilege is truly separated from root, as tests
539 	 * make assumptions about when privilege will be present.  In
540 	 * particular, VFS-related tests need to manage uids in order to
541 	 * force the use of privilege, and will likely need checking.
542 	 */
543 	if (getuid() != 0 && geteuid() != 0)
544 		errx(-1, "must be run as root");
545 
546 	/*
547 	 * Run each test four times, varying whether the process is running
548 	 * as root and in jail in order to test all possible combinations.
549 	 */
550 	for (i = 0; i < tests_count; i++) {
551 		run(&tests[i], 0, 0);
552 		run(&tests[i], 0, 1);
553 		run(&tests[i], 1, 0);
554 		run(&tests[i], 1, 1);
555 	}
556 	return (something_failed ? EXIT_FAILURE : EXIT_SUCCESS);
557 }
558