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_ipsec_pfkey", NULL
, priv_netinet_ipsec_pfkey
, NULL
},
140 { "priv_netinet_ipsec_policy4_bypass",
141 priv_netinet_ipsec_policy4_bypass_setup
,
142 priv_netinet_ipsec_policy4_bypass
,
143 priv_netinet_ipsec_policy_bypass_cleanup
},
145 { "priv_netinet_ipsec_policy6_bypass",
146 priv_netinet_ipsec_policy6_bypass_setup
,
147 priv_netinet_ipsec_policy6_bypass
,
148 priv_netinet_ipsec_policy_bypass_cleanup
},
150 { "priv_netinet_ipsec_policy4_entrust",
151 priv_netinet_ipsec_policy4_entrust_setup
,
152 priv_netinet_ipsec_policy4_entrust
,
153 priv_netinet_ipsec_policy_entrust_cleanup
},
155 { "priv_netinet_ipsec_policy6_entrust",
156 priv_netinet_ipsec_policy6_entrust_setup
,
157 priv_netinet_ipsec_policy6_entrust
,
158 priv_netinet_ipsec_policy_entrust_cleanup
},
160 { "priv_netinet_raw", priv_netinet_raw_setup
, priv_netinet_raw
,
161 priv_netinet_raw_cleanup
},
163 { "priv_proc_setlogin", priv_proc_setlogin_setup
, priv_proc_setlogin
,
164 priv_proc_setlogin_cleanup
},
166 { "priv_proc_setrlimit_raisemax", priv_proc_setrlimit_setup
,
167 priv_proc_setrlimit_raisemax
, priv_proc_setrlimit_cleanup
},
169 { "priv_proc_setrlimit_raisecur", priv_proc_setrlimit_setup
,
170 priv_proc_setrlimit_raisecur
, priv_proc_setrlimit_cleanup
},
172 { "priv_proc_setrlimit_raisecur_nopriv", priv_proc_setrlimit_setup
,
173 priv_proc_setrlimit_raisecur_nopriv
,
174 priv_proc_setrlimit_cleanup
},
176 { "priv_sched_rtprio_curproc_normal", priv_sched_rtprio_setup
,
177 priv_sched_rtprio_curproc_normal
, priv_sched_rtprio_cleanup
},
179 { "priv_sched_rtprio_curproc_idle", priv_sched_rtprio_setup
,
180 priv_sched_rtprio_curproc_idle
, priv_sched_rtprio_cleanup
},
182 { "priv_sched_rtprio_curproc_realtime", priv_sched_rtprio_setup
,
183 priv_sched_rtprio_curproc_realtime
, priv_sched_rtprio_cleanup
},
185 { "priv_sched_rtprio_myproc_normal", priv_sched_rtprio_setup
,
186 priv_sched_rtprio_myproc_normal
, priv_sched_rtprio_cleanup
},
188 { "priv_sched_rtprio_myproc_idle", priv_sched_rtprio_setup
,
189 priv_sched_rtprio_myproc_idle
, priv_sched_rtprio_cleanup
},
191 { "priv_sched_rtprio_myproc_realtime", priv_sched_rtprio_setup
,
192 priv_sched_rtprio_myproc_realtime
, priv_sched_rtprio_cleanup
},
194 { "priv_sched_rtprio_aproc_normal", priv_sched_rtprio_setup
,
195 priv_sched_rtprio_aproc_normal
, priv_sched_rtprio_cleanup
},
197 { "priv_sched_rtprio_aproc_idle", priv_sched_rtprio_setup
,
198 priv_sched_rtprio_aproc_idle
, priv_sched_rtprio_cleanup
},
200 { "priv_sched_rtprio_aproc_realtime", priv_sched_rtprio_setup
,
201 priv_sched_rtprio_aproc_realtime
, priv_sched_rtprio_cleanup
},
203 { "priv_sched_setpriority_curproc", priv_sched_setpriority_setup
,
204 priv_sched_setpriority_curproc
, priv_sched_setpriority_cleanup
},
206 { "priv_sched_setpriority_myproc", priv_sched_setpriority_setup
,
207 priv_sched_setpriority_myproc
, priv_sched_setpriority_cleanup
},
209 { "priv_sched_setpriority_aproc", priv_sched_setpriority_setup
,
210 priv_sched_setpriority_aproc
, priv_sched_setpriority_cleanup
},
212 { "priv_settimeofday", priv_settimeofday_setup
, priv_settimeofday
,
213 priv_settimeofday_cleanup
},
215 { "priv_sysctl_write", priv_sysctl_write_setup
, priv_sysctl_write
,
216 priv_sysctl_write_cleanup
},
218 { "priv_sysctl_writejail", priv_sysctl_write_setup
,
219 priv_sysctl_writejail
, priv_sysctl_write_cleanup
},
221 { "priv_vfs_chflags_froot_uflags", priv_vfs_chflags_froot_setup
,
222 priv_vfs_chflags_froot_uflags
, priv_vfs_chflags_cleanup
},
224 { "priv_vfs_chflags_froot_sflags", priv_vfs_chflags_froot_setup
,
225 priv_vfs_chflags_froot_sflags
, priv_vfs_chflags_cleanup
},
227 { "priv_vfs_chflags_fowner_uflags", priv_vfs_chflags_fowner_setup
,
228 priv_vfs_chflags_fowner_uflags
, priv_vfs_chflags_cleanup
},
230 { "priv_vfs_chflags_fowner_sflags", priv_vfs_chflags_fowner_setup
,
231 priv_vfs_chflags_fowner_sflags
, priv_vfs_chflags_cleanup
},
233 { "priv_vfs_chflags_fother_uflags", priv_vfs_chflags_fother_setup
,
234 priv_vfs_chflags_fother_uflags
, priv_vfs_chflags_cleanup
},
236 { "priv_vfs_chflags_fother_sflags", priv_vfs_chflags_fother_setup
,
237 priv_vfs_chflags_fother_sflags
, priv_vfs_chflags_cleanup
},
239 { "priv_vfs_chmod_froot", priv_vfs_chmod_froot_setup
,
240 priv_vfs_chmod_froot
, priv_vfs_chmod_cleanup
},
242 { "priv_vfs_chmod_fowner", priv_vfs_chmod_fowner_setup
,
243 priv_vfs_chmod_fowner
, priv_vfs_chmod_cleanup
},
245 { "priv_vfs_chmod_fother", priv_vfs_chmod_fother_setup
,
246 priv_vfs_chmod_fother
, priv_vfs_chmod_cleanup
},
248 { "priv_vfs_chown_uid", priv_vfs_chown_uid_setup
, priv_vfs_chown_uid
,
249 priv_vfs_chown_cleanup
},
251 { "priv_vfs_chown_mygid", priv_vfs_chown_mygid_setup
,
252 priv_vfs_chown_mygid
, priv_vfs_chown_cleanup
},
254 { "priv_vfs_chown_othergid", priv_vfs_chown_othergid_setup
,
255 priv_vfs_chown_othergid
, priv_vfs_chown_cleanup
},
257 { "priv_vfs_chroot", priv_vfs_chroot_setup
, priv_vfs_chroot
,
258 priv_vfs_chroot_cleanup
},
260 { "priv_vfs_clearsugid_chgrp", priv_vfs_clearsugid_setup
,
261 priv_vfs_clearsugid_chgrp
, priv_vfs_clearsugid_cleanup
},
263 { "priv_vfs_clearsugid_extattr", priv_vfs_clearsugid_setup
,
264 priv_vfs_clearsugid_extattr
, priv_vfs_clearsugid_cleanup
},
266 { "priv_vfs_clearsugid_write", priv_vfs_clearsugid_setup
,
267 priv_vfs_clearsugid_write
, priv_vfs_clearsugid_cleanup
},
269 { "priv_vfs_extattr_system", priv_vfs_extattr_system_setup
,
270 priv_vfs_extattr_system
, priv_vfs_extattr_system_cleanup
},
272 { "priv_vfs_fhopen", priv_vfs_fhopen_setup
, priv_vfs_fhopen
,
273 priv_vfs_fhopen_cleanup
},
275 { "priv_vfs_fhstat", priv_vfs_fhstat_setup
, priv_vfs_fhstat
,
276 priv_vfs_fhstat_cleanup
},
278 { "priv_vfs_fhstatfs", priv_vfs_fhstatfs_setup
, priv_vfs_fhstatfs
,
279 priv_vfs_fhstatfs_cleanup
},
281 { "priv_vfs_generation", priv_vfs_generation_setup
,
282 priv_vfs_generation
, priv_vfs_generation_cleanup
},
284 { "priv_vfs_getfh", priv_vfs_getfh_setup
, priv_vfs_getfh
,
285 priv_vfs_getfh_cleanup
},
287 { "priv_vfs_readwrite_fowner", priv_vfs_readwrite_fowner_setup
,
288 priv_vfs_readwrite_fowner
, priv_vfs_readwrite_cleanup
},
290 { "priv_vfs_readwrite_fgroup", priv_vfs_readwrite_fgroup_setup
,
291 priv_vfs_readwrite_fgroup
, priv_vfs_readwrite_cleanup
},
293 { "priv_vfs_readwrite_fother", priv_vfs_readwrite_fother_setup
,
294 priv_vfs_readwrite_fother
, priv_vfs_readwrite_cleanup
},
296 { "priv_vfs_setgid_fowner", priv_vfs_setgid_fowner_setup
,
297 priv_vfs_setgid_fowner
, priv_vfs_setgid_cleanup
},
299 { "priv_vfs_setgid_fother", priv_vfs_setgid_fother_setup
,
300 priv_vfs_setgid_fother
, priv_vfs_setgid_cleanup
},
302 { "priv_vfs_stickyfile_dir_fowner",
303 priv_vfs_stickyfile_dir_fowner_setup
,
304 priv_vfs_stickyfile_dir_fowner
,
305 priv_vfs_stickyfile_dir_cleanup
},
307 { "priv_vfs_stickyfile_dir_fother",
308 priv_vfs_stickyfile_dir_fother_setup
,
309 priv_vfs_stickyfile_dir_fother
,
310 priv_vfs_stickyfile_dir_cleanup
},
312 { "priv_vfs_stickyfile_file_fowner",
313 priv_vfs_stickyfile_file_fowner_setup
,
314 priv_vfs_stickyfile_file_fowner
,
315 priv_vfs_stickyfile_file_cleanup
},
317 { "priv_vfs_stickyfile_file_fother",
318 priv_vfs_stickyfile_file_fother_setup
,
319 priv_vfs_stickyfile_file_fother
,
320 priv_vfs_stickyfile_file_cleanup
},
322 { "priv_vfs_utimes_froot", priv_vfs_utimes_froot_setup
,
323 priv_vfs_utimes_froot
, priv_vfs_utimes_cleanup
},
325 { "priv_vfs_utimes_froot_null", priv_vfs_utimes_froot_setup
,
326 priv_vfs_utimes_froot_null
, priv_vfs_utimes_cleanup
},
328 { "priv_vfs_utimes_fowner", priv_vfs_utimes_fowner_setup
,
329 priv_vfs_utimes_fowner
, priv_vfs_utimes_cleanup
},
331 { "priv_vfs_utimes_fowner_null", priv_vfs_utimes_fowner_setup
,
332 priv_vfs_utimes_fowner_null
, priv_vfs_utimes_cleanup
},
334 { "priv_vfs_utimes_fother", priv_vfs_utimes_fother_setup
,
335 priv_vfs_utimes_fother
, priv_vfs_utimes_cleanup
},
337 { "priv_vfs_utimes_fother_null", priv_vfs_utimes_fother_setup
,
338 priv_vfs_utimes_fother_null
, priv_vfs_utimes_cleanup
},
340 { "priv_vm_madv_protect", priv_vm_madv_protect_setup
,
341 priv_vm_madv_protect
, priv_vm_madv_protect_cleanup
},
343 { "priv_vm_mlock", priv_vm_mlock_setup
, priv_vm_mlock
,
344 priv_vm_mlock_cleanup
},
346 { "priv_vm_munlock", priv_vm_munlock_setup
, priv_vm_munlock
,
347 priv_vm_munlock_cleanup
},
350 static int tests_count
= sizeof(tests
) / sizeof(struct test
);
353 expect(const char *test
, int error
, int expected_error
, int expected_errno
)
357 if (expected_error
!= 0)
358 warnx("%s: returned 0", test
);
360 if (expected_error
== 0)
361 warn("%s: returned (%d, %d)", test
, error
, errno
);
362 else if (expected_errno
!= errno
)
363 warn("%s: returned (%d, %d)", test
, error
, errno
);
368 setup_dir(const char *test
, char *dpathp
, uid_t uid
, gid_t gid
, mode_t mode
)
371 strcpy(dpathp
, "/tmp/priv.XXXXXXXXXXX");
372 if (mkdtemp(dpathp
) == NULL
)
373 err(-1, "test %s: mkdtemp", test
);
375 if (chown(dpathp
, uid
, gid
) < 0)
376 err(-1, "test %s: chown(%s, %d, %d)", test
, dpathp
, uid
,
379 if (chmod(dpathp
, mode
) < 0)
380 err(-1, "test %s: chmod(%s, 0%o)", test
, dpathp
, mode
);
384 setup_file(const char *test
, char *fpathp
, uid_t uid
, gid_t gid
, mode_t mode
)
388 strcpy(fpathp
, "/tmp/priv.XXXXXXXXXXX");
389 fd
= mkstemp(fpathp
);
391 err(-1, "test %s: mkstemp", test
);
393 if (fchown(fd
, uid
, gid
) < 0)
394 err(-1, "test %s: fchown(%s, %d, %d)", test
, fpathp
, uid
,
397 if (fchmod(fd
, mode
) < 0)
398 err(-1, "test %s: chmod(%s, 0%o)", test
, fpathp
, mode
);
404 * Irrevocably set credentials to specific uid and gid.
407 set_creds(const char *test
, uid_t uid
, gid_t gid
)
409 gid_t gids
[1] = { gid
};
412 err(-1, "test %s: setegid(%d)", test
, gid
);
413 if (setgroups(sizeof(gids
)/sizeof(gid_t
), gids
) < 0)
414 err(-1, "test %s: setgroups(%d)", test
, gid
);
416 err(-1, "test %s: seteuid(%d)", test
, uid
);
420 enter_jail(const char *test
)
424 bzero(&j
, sizeof(j
));
428 j
.ip_number
= htonl(INADDR_LOOPBACK
);
430 err(-1, "test %s: jail", test
);
434 run_child(struct test
*test
, int asroot
, int injail
)
437 setprogname(test
->t_name
);
439 enter_jail(test
->t_name
);
441 set_creds(test
->t_name
, UID_OWNER
, GID_OWNER
);
442 test
->t_test_func(asroot
, injail
, test
);
446 * Run a test in a particular credential context -- always call the setup and
447 * cleanup routines; if setup succeeds, also run the test. Test cleanup must
448 * handle cases where the setup has failed, so may need to maintain their own
449 * state in order to know what needs cleaning up (such as whether temporary
450 * files were created).
453 run(struct test
*test
, int asroot
, int injail
)
457 if (test
->t_setup_func
!= NULL
) {
458 if ((test
->t_setup_func
)(asroot
, injail
, test
) != 0) {
459 warnx("run(%s, %d, %d) setup failed", test
->t_name
,
467 if (childpid
== -1) {
468 warn("run(%s, %d, %d) fork failed", test
->t_name
, asroot
,
473 run_child(test
, asroot
, injail
);
479 pid
= waitpid(childpid
, NULL
, 0);
481 warn("test: waitpid %s", test
->t_name
);
489 if (test
->t_cleanup_func
!= NULL
)
490 test
->t_cleanup_func(asroot
, injail
, test
);
494 main(int argc
, char *argv
[])
499 * This test suite will need to become quite a bit more enlightened
500 * if the notion of privilege is truly separated from root, as tests
501 * make assumptions about when privilege will be present. In
502 * particular, VFS-related tests need to manage uids in order to
503 * force the use of privilege, and will likely need checking.
505 if (getuid() != 0 && geteuid() != 0)
506 errx(-1, "priv: must be run as root");
509 * Run each test four times, varying whether the process is running
510 * as root and in jail in order to test all possible combinations.
512 for (i
= 0; i
< tests_count
; i
++) {
513 run(&tests
[i
], 0, 0);
514 run(&tests
[i
], 0, 1);
515 run(&tests
[i
], 1, 0);
516 run(&tests
[i
], 1, 1);