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