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