2 * Copyright (c) 2006 nCircle Network Security, Inc.
3 * Copyright (c) 2007 Robert N. M. Watson
6 * This software was developed by Robert N. M. Watson for the TrustedBSD
7 * Project under contract to nCircle Network Security, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
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.
39 #include <sys/param.h>
44 #include <netinet/in.h>
56 * Registration table of privilege tests. Each test registers a name, a test
57 * function, and a cleanup function to run after the test has completed,
58 * regardless of success/failure.
60 static struct test tests[] = {
61 { "priv_acct_enable", priv_acct_setup, priv_acct_enable,
64 { "priv_acct_disable", priv_acct_setup, priv_acct_disable,
67 { "priv_acct_rotate", priv_acct_setup, priv_acct_rotate,
70 { "priv_acct_noopdisable", priv_acct_setup, priv_acct_noopdisable,
73 { "priv_adjtime_set", priv_adjtime_setup, priv_adjtime_set,
74 priv_adjtime_cleanup },
76 { "priv_audit_submit", priv_audit_submit_setup, priv_audit_submit,
77 priv_audit_submit_cleanup },
79 { "priv_audit_control", priv_audit_control_setup, priv_audit_control,
80 priv_audit_control_cleanup },
82 { "priv_audit_getaudit", priv_audit_getaudit_setup,
83 priv_audit_getaudit, priv_audit_getaudit_cleanup },
85 { "priv_audit_getaudit_addr", priv_audit_getaudit_setup,
86 priv_audit_getaudit_addr, priv_audit_getaudit_cleanup },
88 { "priv_audit_setaudit", priv_audit_setaudit_setup,
89 priv_audit_setaudit, priv_audit_setaudit_cleanup },
91 { "priv_audit_setaudit_addr", priv_audit_setaudit_setup,
92 priv_audit_setaudit_addr, priv_audit_setaudit_cleanup },
94 { "priv_clock_settime", priv_clock_settime_setup, priv_clock_settime,
95 priv_clock_settime_cleanup },
97 { "priv_cred_setuid", priv_cred_setup, priv_cred_setuid,
100 { "priv_cred_seteuid", priv_cred_setup, priv_cred_seteuid,
103 { "priv_cred_setgid", priv_cred_setup, priv_cred_setgid,
106 { "priv_cred_setegid", priv_cred_setup, priv_cred_setegid,
109 { "priv_cred_setgroups", priv_cred_setup, priv_cred_setgroups,
112 { "priv_cred_setreuid", priv_cred_setup, priv_cred_setreuid,
115 { "priv_cred_setregid", priv_cred_setup, priv_cred_setregid,
118 { "priv_cred_setresuid", priv_cred_setup, priv_cred_setresuid,
121 { "priv_cred_setresgid", priv_cred_setup, priv_cred_setresgid,
124 { "priv_io", priv_io_setup, priv_io, priv_io_cleanup },
126 { "priv_kenv_set", priv_kenv_set_setup, priv_kenv_set,
127 priv_kenv_set_cleanup },
129 { "priv_kenv_unset", priv_kenv_unset_setup, priv_kenv_unset,
130 priv_kenv_unset_cleanup },
132 { "priv_msgbuf_privonly", priv_msgbuf_privonly_setup,
133 priv_msgbuf_privonly, priv_msgbuf_cleanup },
135 { "priv_msgbuf_unprivok", priv_msgbuf_unprivok_setup,
136 priv_msgbuf_unprivok, priv_msgbuf_cleanup },
138 { "priv_netinet_raw", priv_netinet_raw_setup, priv_netinet_raw,
139 priv_netinet_raw_cleanup },
141 { "priv_proc_setlogin", priv_proc_setlogin_setup, priv_proc_setlogin,
142 priv_proc_setlogin_cleanup },
144 { "priv_proc_setrlimit_raisemax", priv_proc_setrlimit_setup,
145 priv_proc_setrlimit_raisemax, priv_proc_setrlimit_cleanup },
147 { "priv_proc_setrlimit_raisecur", priv_proc_setrlimit_setup,
148 priv_proc_setrlimit_raisecur, priv_proc_setrlimit_cleanup },
150 { "priv_proc_setrlimit_raisecur_nopriv", priv_proc_setrlimit_setup,
151 priv_proc_setrlimit_raisecur_nopriv,
152 priv_proc_setrlimit_cleanup },
154 { "priv_sched_rtprio_curproc_normal", priv_sched_rtprio_setup,
155 priv_sched_rtprio_curproc_normal, priv_sched_rtprio_cleanup },
157 { "priv_sched_rtprio_curproc_idle", priv_sched_rtprio_setup,
158 priv_sched_rtprio_curproc_idle, priv_sched_rtprio_cleanup },
160 { "priv_sched_rtprio_curproc_realtime", priv_sched_rtprio_setup,
161 priv_sched_rtprio_curproc_realtime, priv_sched_rtprio_cleanup },
163 { "priv_sched_rtprio_myproc_normal", priv_sched_rtprio_setup,
164 priv_sched_rtprio_myproc_normal, priv_sched_rtprio_cleanup },
166 { "priv_sched_rtprio_myproc_idle", priv_sched_rtprio_setup,
167 priv_sched_rtprio_myproc_idle, priv_sched_rtprio_cleanup },
169 { "priv_sched_rtprio_myproc_realtime", priv_sched_rtprio_setup,
170 priv_sched_rtprio_myproc_realtime, priv_sched_rtprio_cleanup },
172 { "priv_sched_rtprio_aproc_normal", priv_sched_rtprio_setup,
173 priv_sched_rtprio_aproc_normal, priv_sched_rtprio_cleanup },
175 { "priv_sched_rtprio_aproc_idle", priv_sched_rtprio_setup,
176 priv_sched_rtprio_aproc_idle, priv_sched_rtprio_cleanup },
178 { "priv_sched_rtprio_aproc_realtime", priv_sched_rtprio_setup,
179 priv_sched_rtprio_aproc_realtime, priv_sched_rtprio_cleanup },
181 { "priv_sched_setpriority_curproc", priv_sched_setpriority_setup,
182 priv_sched_setpriority_curproc, priv_sched_setpriority_cleanup },
184 { "priv_sched_setpriority_myproc", priv_sched_setpriority_setup,
185 priv_sched_setpriority_myproc, priv_sched_setpriority_cleanup },
187 { "priv_sched_setpriority_aproc", priv_sched_setpriority_setup,
188 priv_sched_setpriority_aproc, priv_sched_setpriority_cleanup },
190 { "priv_settimeofday", priv_settimeofday_setup, priv_settimeofday,
191 priv_settimeofday_cleanup },
193 { "priv_sysctl_write", priv_sysctl_write_setup, priv_sysctl_write,
194 priv_sysctl_write_cleanup },
196 { "priv_sysctl_writejail", priv_sysctl_write_setup,
197 priv_sysctl_writejail, priv_sysctl_write_cleanup },
199 { "priv_vfs_chflags_froot_uflags", priv_vfs_chflags_froot_setup,
200 priv_vfs_chflags_froot_uflags, priv_vfs_chflags_cleanup },
202 { "priv_vfs_chflags_froot_sflags", priv_vfs_chflags_froot_setup,
203 priv_vfs_chflags_froot_sflags, priv_vfs_chflags_cleanup },
205 { "priv_vfs_chflags_fowner_uflags", priv_vfs_chflags_fowner_setup,
206 priv_vfs_chflags_fowner_uflags, priv_vfs_chflags_cleanup },
208 { "priv_vfs_chflags_fowner_sflags", priv_vfs_chflags_fowner_setup,
209 priv_vfs_chflags_fowner_sflags, priv_vfs_chflags_cleanup },
211 { "priv_vfs_chflags_fother_uflags", priv_vfs_chflags_fother_setup,
212 priv_vfs_chflags_fother_uflags, priv_vfs_chflags_cleanup },
214 { "priv_vfs_chflags_fother_sflags", priv_vfs_chflags_fother_setup,
215 priv_vfs_chflags_fother_sflags, priv_vfs_chflags_cleanup },
217 { "priv_vfs_chmod_froot", priv_vfs_chmod_froot_setup,
218 priv_vfs_chmod_froot, priv_vfs_chmod_cleanup },
220 { "priv_vfs_chmod_fowner", priv_vfs_chmod_fowner_setup,
221 priv_vfs_chmod_fowner, priv_vfs_chmod_cleanup },
223 { "priv_vfs_chmod_fother", priv_vfs_chmod_fother_setup,
224 priv_vfs_chmod_fother, priv_vfs_chmod_cleanup },
226 { "priv_vfs_chown_uid", priv_vfs_chown_uid_setup, priv_vfs_chown_uid,
227 priv_vfs_chown_cleanup },
229 { "priv_vfs_chown_mygid", priv_vfs_chown_mygid_setup,
230 priv_vfs_chown_mygid, priv_vfs_chown_cleanup },
232 { "priv_vfs_chown_othergid", priv_vfs_chown_othergid_setup,
233 priv_vfs_chown_othergid, priv_vfs_chown_cleanup },
235 { "priv_vfs_chroot", priv_vfs_chroot_setup, priv_vfs_chroot,
236 priv_vfs_chroot_cleanup },
238 { "priv_vfs_clearsugid_chgrp", priv_vfs_clearsugid_setup,
239 priv_vfs_clearsugid_chgrp, priv_vfs_clearsugid_cleanup },
241 { "priv_vfs_clearsugid_extattr", priv_vfs_clearsugid_setup,
242 priv_vfs_clearsugid_extattr, priv_vfs_clearsugid_cleanup },
244 { "priv_vfs_clearsugid_write", priv_vfs_clearsugid_setup,
245 priv_vfs_clearsugid_write, priv_vfs_clearsugid_cleanup },
247 { "priv_vfs_extattr_system", priv_vfs_extattr_system_setup,
248 priv_vfs_extattr_system, priv_vfs_extattr_system_cleanup },
250 { "priv_vfs_fhopen", priv_vfs_fhopen_setup, priv_vfs_fhopen,
251 priv_vfs_fhopen_cleanup },
253 { "priv_vfs_fhstat", priv_vfs_fhstat_setup, priv_vfs_fhstat,
254 priv_vfs_fhstat_cleanup },
256 { "priv_vfs_fhstatfs", priv_vfs_fhstatfs_setup, priv_vfs_fhstatfs,
257 priv_vfs_fhstatfs_cleanup },
259 { "priv_vfs_generation", priv_vfs_generation_setup,
260 priv_vfs_generation, priv_vfs_generation_cleanup },
262 { "priv_vfs_getfh", priv_vfs_getfh_setup, priv_vfs_getfh,
263 priv_vfs_getfh_cleanup },
265 { "priv_vfs_readwrite_fowner", priv_vfs_readwrite_fowner_setup,
266 priv_vfs_readwrite_fowner, priv_vfs_readwrite_cleanup },
268 { "priv_vfs_readwrite_fgroup", priv_vfs_readwrite_fgroup_setup,
269 priv_vfs_readwrite_fgroup, priv_vfs_readwrite_cleanup },
271 { "priv_vfs_readwrite_fother", priv_vfs_readwrite_fother_setup,
272 priv_vfs_readwrite_fother, priv_vfs_readwrite_cleanup },
274 { "priv_vfs_setgid_fowner", priv_vfs_setgid_fowner_setup,
275 priv_vfs_setgid_fowner, priv_vfs_setgid_cleanup },
277 { "priv_vfs_setgid_fother", priv_vfs_setgid_fother_setup,
278 priv_vfs_setgid_fother, priv_vfs_setgid_cleanup },
280 { "priv_vfs_stickyfile_dir_fowner",
281 priv_vfs_stickyfile_dir_fowner_setup,
282 priv_vfs_stickyfile_dir_fowner,
283 priv_vfs_stickyfile_dir_cleanup },
285 { "priv_vfs_stickyfile_dir_fother",
286 priv_vfs_stickyfile_dir_fother_setup,
287 priv_vfs_stickyfile_dir_fother,
288 priv_vfs_stickyfile_dir_cleanup },
290 { "priv_vfs_stickyfile_file_fowner",
291 priv_vfs_stickyfile_file_fowner_setup,
292 priv_vfs_stickyfile_file_fowner,
293 priv_vfs_stickyfile_file_cleanup },
295 { "priv_vfs_stickyfile_file_fother",
296 priv_vfs_stickyfile_file_fother_setup,
297 priv_vfs_stickyfile_file_fother,
298 priv_vfs_stickyfile_file_cleanup },
300 { "priv_vfs_utimes_froot", priv_vfs_utimes_froot_setup,
301 priv_vfs_utimes_froot, priv_vfs_utimes_cleanup },
303 { "priv_vfs_utimes_froot_null", priv_vfs_utimes_froot_setup,
304 priv_vfs_utimes_froot_null, priv_vfs_utimes_cleanup },
306 { "priv_vfs_utimes_fowner", priv_vfs_utimes_fowner_setup,
307 priv_vfs_utimes_fowner, priv_vfs_utimes_cleanup },
309 { "priv_vfs_utimes_fowner_null", priv_vfs_utimes_fowner_setup,
310 priv_vfs_utimes_fowner_null, priv_vfs_utimes_cleanup },
312 { "priv_vfs_utimes_fother", priv_vfs_utimes_fother_setup,
313 priv_vfs_utimes_fother, priv_vfs_utimes_cleanup },
315 { "priv_vfs_utimes_fother_null", priv_vfs_utimes_fother_setup,
316 priv_vfs_utimes_fother_null, priv_vfs_utimes_cleanup },
318 { "priv_vm_madv_protect", priv_vm_madv_protect_setup,
319 priv_vm_madv_protect, priv_vm_madv_protect_cleanup },
321 { "priv_vm_mlock", priv_vm_mlock_setup, priv_vm_mlock,
322 priv_vm_mlock_cleanup },
324 { "priv_vm_munlock", priv_vm_munlock_setup, priv_vm_munlock,
325 priv_vm_munlock_cleanup },
328 static int tests_count = sizeof(tests) / sizeof(struct test);
331 expect(const char *test, int error, int expected_error, int expected_errno)
335 if (expected_error != 0)
336 warnx("%s: returned 0", test);
338 if (expected_error == 0)
339 warn("%s: returned (%d, %d)", test, error, errno);
340 else if (expected_errno != errno)
341 warn("%s: returned (%d, %d)", test, error, errno);
346 setup_dir(const char *test, char *dpathp, uid_t uid, gid_t gid, mode_t mode)
349 strcpy(dpathp, "/tmp/priv.XXXXXXXXXXX");
350 if (mkdtemp(dpathp) == NULL)
351 err(-1, "test %s: mkdtemp", test);
353 if (chown(dpathp, uid, gid) < 0)
354 err(-1, "test %s: chown(%s, %d, %d)", test, dpathp, uid,
357 if (chmod(dpathp, mode) < 0)
358 err(-1, "test %s: chmod(%s, 0%o)", test, dpathp, mode);
362 setup_file(const char *test, char *fpathp, uid_t uid, gid_t gid, mode_t mode)
366 strcpy(fpathp, "/tmp/priv.XXXXXXXXXXX");
367 fd = mkstemp(fpathp);
369 err(-1, "test %s: mkstemp", test);
371 if (fchown(fd, uid, gid) < 0)
372 err(-1, "test %s: fchown(%s, %d, %d)", test, fpathp, uid,
375 if (fchmod(fd, mode) < 0)
376 err(-1, "test %s: chmod(%s, 0%o)", test, fpathp, mode);
382 * Irrevocably set credentials to specific uid and gid.
385 set_creds(const char *test, uid_t uid, gid_t gid)
387 gid_t gids[1] = { gid };
390 err(-1, "test %s: setegid(%d)", test, gid);
391 if (setgroups(sizeof(gids)/sizeof(gid_t), gids) < 0)
392 err(-1, "test %s: setgroups(%d)", test, gid);
394 err(-1, "test %s: seteuid(%d)", test, uid);
398 enter_jail(const char *test)
402 bzero(&j, sizeof(j));
406 j.ip_number = htonl(INADDR_LOOPBACK);
408 err(-1, "test %s: jail", test);
412 run_child(struct test *test, int asroot, int injail)
415 setprogname(test->t_name);
417 enter_jail(test->t_name);
419 set_creds(test->t_name, UID_OWNER, GID_OWNER);
420 test->t_test_func(asroot, injail, test);
424 * Run a test in a particular credential context -- always call the setup and
425 * cleanup routines; if setup succeeds, also run the test. Test cleanup must
426 * handle cases where the setup has failed, so may need to maintain their own
427 * state in order to know what needs cleaning up (such as whether temporary
428 * files were created).
431 run(struct test *test, int asroot, int injail)
435 if (test->t_setup_func != NULL) {
436 if ((test->t_setup_func)(asroot, injail, test) != 0) {
437 warnx("run(%s, %d, %d) setup failed", test->t_name,
445 if (childpid == -1) {
446 warn("run(%s, %d, %d) fork failed", test->t_name, asroot,
451 run_child(test, asroot, injail);
457 pid = waitpid(childpid, NULL, 0);
459 warn("test: waitpid %s", test->t_name);
467 if (test->t_cleanup_func != NULL)
468 test->t_cleanup_func(asroot, injail, test);
472 main(int argc, char *argv[])
477 * This test suite will need to become quite a bit more enlightened
478 * if the notion of privilege is truly separated from root, as tests
479 * make assumptions about when privilege will be present. In
480 * particular, VFS-related tests need to manage uids in order to
481 * force the use of privilege, and will likely need checking.
483 if (getuid() != 0 && geteuid() != 0)
484 errx(-1, "priv: must be run as root");
487 * Run each test four times, varying whether the process is running
488 * as root and in jail in order to test all possible combinations.
490 for (i = 0; i < tests_count; i++) {
491 run(&tests[i], 0, 0);
492 run(&tests[i], 0, 1);
493 run(&tests[i], 1, 0);
494 run(&tests[i], 1, 1);