From 2f5eb093a49d608441a859f9e1771c6dbbc128e0 Mon Sep 17 00:00:00 2001 From: rwatson Date: Sun, 9 Sep 2007 23:08:39 +0000 Subject: Enhance and expand kernel privilege regression tests in support of work present in FreeBSD 7.0 to refine the kernel privilege model: - Introduce support for jail as a testing variable, in order to confirm that privileges are properly restricted in the jail environment. - Restructure overall testing approach so that privilege and jail conditions are set in the testing infrastructure before tests are invoked, and done so in a custom-created process to isolate the impact of tests from each other in a more consistent way. - Tests now provide setup and cleanup hooks that occur before and after the test runs. - New privilege tests are now present for several audit privileges, several credential management privileges, dmesg buffer reading privilege, and netinet raw socket creation. - Other existing tests are restructured and generally improved as a result of better framework structure and jail as a variable. For exampe, we now test that certain sysctls are writable only outside jail, while others are writable within jail. On a similar note, privileges relating to setting UFS file flags are now better exercised, as with the right to chmod and utimes files. Approved by: re (bmah) Obtained from: TrustedBSD Project --- tools/regression/priv/Makefile | 20 +- tools/regression/priv/main.c | 455 +++++++++++++++++++---- tools/regression/priv/main.h | 299 +++++++++++++-- tools/regression/priv/priv_acct.c | 220 +++++------ tools/regression/priv/priv_adjtime.c | 59 +-- tools/regression/priv/priv_audit_control.c | 85 +++++ tools/regression/priv/priv_audit_getaudit.c | 102 +++++ tools/regression/priv/priv_audit_setaudit.c | 109 ++++++ tools/regression/priv/priv_audit_submit.c | 88 +++++ tools/regression/priv/priv_clock_settime.c | 56 +-- tools/regression/priv/priv_cred.c | 208 +++++++++++ tools/regression/priv/priv_io.c | 115 +++--- tools/regression/priv/priv_kenv_set.c | 42 ++- tools/regression/priv/priv_kenv_unset.c | 52 +-- tools/regression/priv/priv_msgbuf.c | 152 ++++++++ tools/regression/priv/priv_netinet_raw.c | 82 ++++ tools/regression/priv/priv_proc_setlogin.c | 65 ++-- tools/regression/priv/priv_proc_setrlimit.c | 189 ++++++---- tools/regression/priv/priv_sched_rtprio.c | 353 +++++++++++------- tools/regression/priv/priv_sched_setpriority.c | 186 +++++----- tools/regression/priv/priv_settimeofday.c | 55 +-- tools/regression/priv/priv_sysctl_write.c | 109 ++++-- tools/regression/priv/priv_vfs_admin.c | 328 ---------------- tools/regression/priv/priv_vfs_chflags.c | 254 +++++++++++++ tools/regression/priv/priv_vfs_chmod.c | 146 ++++++++ tools/regression/priv/priv_vfs_chown.c | 194 +++++----- tools/regression/priv/priv_vfs_chroot.c | 36 +- tools/regression/priv/priv_vfs_clearsugid.c | 209 ++++------- tools/regression/priv/priv_vfs_extattr_system.c | 78 ++-- tools/regression/priv/priv_vfs_fhopen.c | 79 ++-- tools/regression/priv/priv_vfs_fhstat.c | 74 ++-- tools/regression/priv/priv_vfs_fhstatfs.c | 78 ++-- tools/regression/priv/priv_vfs_generation.c | 115 +++--- tools/regression/priv/priv_vfs_getfh.c | 51 +-- tools/regression/priv/priv_vfs_read_write.c | 475 +++++++++--------------- tools/regression/priv/priv_vfs_setgid.c | 148 ++++---- tools/regression/priv/priv_vfs_stickyfile.c | 210 +++++++---- tools/regression/priv/priv_vfs_utimes.c | 224 +++++++++++ tools/regression/priv/priv_vm_madv_protect.c | 38 +- tools/regression/priv/priv_vm_mlock.c | 35 +- tools/regression/priv/priv_vm_munlock.c | 36 +- tools/regression/priv/test_utimes.c | 153 -------- 42 files changed, 3850 insertions(+), 2212 deletions(-) create mode 100644 tools/regression/priv/priv_audit_control.c create mode 100644 tools/regression/priv/priv_audit_getaudit.c create mode 100644 tools/regression/priv/priv_audit_setaudit.c create mode 100644 tools/regression/priv/priv_audit_submit.c create mode 100644 tools/regression/priv/priv_cred.c create mode 100644 tools/regression/priv/priv_msgbuf.c create mode 100644 tools/regression/priv/priv_netinet_raw.c delete mode 100644 tools/regression/priv/priv_vfs_admin.c create mode 100644 tools/regression/priv/priv_vfs_chflags.c create mode 100644 tools/regression/priv/priv_vfs_chmod.c create mode 100644 tools/regression/priv/priv_vfs_utimes.c delete mode 100644 tools/regression/priv/test_utimes.c (limited to 'tools/regression') diff --git a/tools/regression/priv/Makefile b/tools/regression/priv/Makefile index 7a8d7a0..2a63ecc 100644 --- a/tools/regression/priv/Makefile +++ b/tools/regression/priv/Makefile @@ -2,21 +2,29 @@ # $FreeBSD$ # -PROG= main +PROG= priv SRCS= main.c \ priv_acct.c \ priv_adjtime.c \ + priv_audit_control.c \ + priv_audit_getaudit.c \ + priv_audit_setaudit.c \ + priv_audit_submit.c \ priv_clock_settime.c \ + priv_cred.c \ priv_io.c \ priv_kenv_set.c \ priv_kenv_unset.c \ + priv_msgbuf.c \ + priv_netinet_raw.c \ priv_proc_setlogin.c \ priv_proc_setrlimit.c \ priv_sched_rtprio.c \ priv_sched_setpriority.c \ priv_settimeofday.c \ priv_sysctl_write.c \ - priv_vfs_admin.c \ + priv_vfs_chflags.c \ + priv_vfs_chmod.c \ priv_vfs_chown.c \ priv_vfs_chroot.c \ priv_vfs_clearsugid.c \ @@ -29,11 +37,11 @@ SRCS= main.c \ priv_vfs_read_write.c \ priv_vfs_setgid.c \ priv_vfs_stickyfile.c \ - priv_vm_mlock.c \ - priv_vm_munlock.c \ + priv_vfs_utimes.c \ priv_vm_madv_protect.c \ - \ - test_utimes.c + priv_vm_mlock.c \ + priv_vm_munlock.c + NO_MAN= WARNS= 3 diff --git a/tools/regression/priv/main.c b/tools/regression/priv/main.c index 90622ad..a9faa98 100644 --- a/tools/regression/priv/main.c +++ b/tools/regression/priv/main.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,16 +31,20 @@ */ /* - * Privilege test framework. Each test is encapsulated on a .c file exporting - * a function that implements the test. Each test is run from its own child - * process, and they are run in sequence one at a time. + * Privilege test framework. Each test is encapsulated on a .c file + * exporting a function that implements the test. Each test is run from its + * own child process, and they are run in sequence one at a time. */ -#include +#include +#include #include #include +#include + #include +#include #include #include #include @@ -48,86 +53,402 @@ #include "main.h" /* - * Common routines used across many tests. + * Registration table of privilege tests. Each test registers a name, a test + * function, and a cleanup function to run after the test has completed, + * regardless of success/failure. */ +static struct test tests[] = { + { "priv_acct_enable", priv_acct_setup, priv_acct_enable, + priv_acct_cleanup }, + + { "priv_acct_disable", priv_acct_setup, priv_acct_disable, + priv_acct_cleanup }, + + { "priv_acct_rotate", priv_acct_setup, priv_acct_rotate, + priv_acct_cleanup }, + + { "priv_acct_noopdisable", priv_acct_setup, priv_acct_noopdisable, + priv_acct_cleanup }, + + { "priv_adjtime_set", priv_adjtime_setup, priv_adjtime_set, + priv_adjtime_cleanup }, + + { "priv_audit_submit", priv_audit_submit_setup, priv_audit_submit, + priv_audit_submit_cleanup }, + + { "priv_audit_control", priv_audit_control_setup, priv_audit_control, + priv_audit_control_cleanup }, + + { "priv_audit_getaudit", priv_audit_getaudit_setup, + priv_audit_getaudit, priv_audit_getaudit_cleanup }, + + { "priv_audit_getaudit_addr", priv_audit_getaudit_setup, + priv_audit_getaudit_addr, priv_audit_getaudit_cleanup }, + + { "priv_audit_setaudit", priv_audit_setaudit_setup, + priv_audit_setaudit, priv_audit_setaudit_cleanup }, + + { "priv_audit_setaudit_addr", priv_audit_setaudit_setup, + priv_audit_setaudit_addr, priv_audit_setaudit_cleanup }, + + { "priv_clock_settime", priv_clock_settime_setup, priv_clock_settime, + priv_clock_settime_cleanup }, + + { "priv_cred_setuid", priv_cred_setup, priv_cred_setuid, + priv_cred_cleanup }, + + { "priv_cred_seteuid", priv_cred_setup, priv_cred_seteuid, + priv_cred_cleanup }, + + { "priv_cred_setgid", priv_cred_setup, priv_cred_setgid, + priv_cred_cleanup }, + + { "priv_cred_setegid", priv_cred_setup, priv_cred_setegid, + priv_cred_cleanup }, + + { "priv_cred_setgroups", priv_cred_setup, priv_cred_setgroups, + priv_cred_cleanup }, + + { "priv_cred_setreuid", priv_cred_setup, priv_cred_setreuid, + priv_cred_cleanup }, + + { "priv_cred_setregid", priv_cred_setup, priv_cred_setregid, + priv_cred_cleanup }, + + { "priv_cred_setresuid", priv_cred_setup, priv_cred_setresuid, + priv_cred_cleanup }, + + { "priv_cred_setresgid", priv_cred_setup, priv_cred_setresgid, + priv_cred_cleanup }, + + { "priv_io", priv_io_setup, priv_io, priv_io_cleanup }, + + { "priv_kenv_set", priv_kenv_set_setup, priv_kenv_set, + priv_kenv_set_cleanup }, + + { "priv_kenv_unset", priv_kenv_unset_setup, priv_kenv_unset, + priv_kenv_unset_cleanup }, + + { "priv_msgbuf_privonly", priv_msgbuf_privonly_setup, + priv_msgbuf_privonly, priv_msgbuf_cleanup }, + + { "priv_msgbuf_unprivok", priv_msgbuf_unprivok_setup, + priv_msgbuf_unprivok, priv_msgbuf_cleanup }, + + { "priv_netinet_raw", priv_netinet_raw_setup, priv_netinet_raw, + priv_netinet_raw_cleanup }, + + { "priv_proc_setlogin", priv_proc_setlogin_setup, priv_proc_setlogin, + priv_proc_setlogin_cleanup }, + + { "priv_proc_setrlimit_raisemax", priv_proc_setrlimit_setup, + priv_proc_setrlimit_raisemax, priv_proc_setrlimit_cleanup }, + + { "priv_proc_setrlimit_raisecur", priv_proc_setrlimit_setup, + priv_proc_setrlimit_raisecur, priv_proc_setrlimit_cleanup }, + + { "priv_proc_setrlimit_raisecur_nopriv", priv_proc_setrlimit_setup, + priv_proc_setrlimit_raisecur_nopriv, + priv_proc_setrlimit_cleanup }, + + { "priv_sched_rtprio_curproc_normal", priv_sched_rtprio_setup, + priv_sched_rtprio_curproc_normal, priv_sched_rtprio_cleanup }, + + { "priv_sched_rtprio_curproc_idle", priv_sched_rtprio_setup, + priv_sched_rtprio_curproc_idle, priv_sched_rtprio_cleanup }, + + { "priv_sched_rtprio_curproc_realtime", priv_sched_rtprio_setup, + priv_sched_rtprio_curproc_realtime, priv_sched_rtprio_cleanup }, + + { "priv_sched_rtprio_myproc_normal", priv_sched_rtprio_setup, + priv_sched_rtprio_myproc_normal, priv_sched_rtprio_cleanup }, + + { "priv_sched_rtprio_myproc_idle", priv_sched_rtprio_setup, + priv_sched_rtprio_myproc_idle, priv_sched_rtprio_cleanup }, + + { "priv_sched_rtprio_myproc_realtime", priv_sched_rtprio_setup, + priv_sched_rtprio_myproc_realtime, priv_sched_rtprio_cleanup }, + + { "priv_sched_rtprio_aproc_normal", priv_sched_rtprio_setup, + priv_sched_rtprio_aproc_normal, priv_sched_rtprio_cleanup }, + + { "priv_sched_rtprio_aproc_idle", priv_sched_rtprio_setup, + priv_sched_rtprio_aproc_idle, priv_sched_rtprio_cleanup }, + + { "priv_sched_rtprio_aproc_realtime", priv_sched_rtprio_setup, + priv_sched_rtprio_aproc_realtime, priv_sched_rtprio_cleanup }, + + { "priv_sched_setpriority_curproc", priv_sched_setpriority_setup, + priv_sched_setpriority_curproc, priv_sched_setpriority_cleanup }, + + { "priv_sched_setpriority_myproc", priv_sched_setpriority_setup, + priv_sched_setpriority_myproc, priv_sched_setpriority_cleanup }, + + { "priv_sched_setpriority_aproc", priv_sched_setpriority_setup, + priv_sched_setpriority_aproc, priv_sched_setpriority_cleanup }, + + { "priv_settimeofday", priv_settimeofday_setup, priv_settimeofday, + priv_settimeofday_cleanup }, + + { "priv_sysctl_write", priv_sysctl_write_setup, priv_sysctl_write, + priv_sysctl_write_cleanup }, + + { "priv_sysctl_writejail", priv_sysctl_write_setup, + priv_sysctl_writejail, priv_sysctl_write_cleanup }, + + { "priv_vfs_chflags_froot_uflags", priv_vfs_chflags_froot_setup, + priv_vfs_chflags_froot_uflags, priv_vfs_chflags_cleanup }, + + { "priv_vfs_chflags_froot_sflags", priv_vfs_chflags_froot_setup, + priv_vfs_chflags_froot_sflags, priv_vfs_chflags_cleanup }, + + { "priv_vfs_chflags_fowner_uflags", priv_vfs_chflags_fowner_setup, + priv_vfs_chflags_fowner_uflags, priv_vfs_chflags_cleanup }, + + { "priv_vfs_chflags_fowner_sflags", priv_vfs_chflags_fowner_setup, + priv_vfs_chflags_fowner_sflags, priv_vfs_chflags_cleanup }, + + { "priv_vfs_chflags_fother_uflags", priv_vfs_chflags_fother_setup, + priv_vfs_chflags_fother_uflags, priv_vfs_chflags_cleanup }, + + { "priv_vfs_chflags_fother_sflags", priv_vfs_chflags_fother_setup, + priv_vfs_chflags_fother_sflags, priv_vfs_chflags_cleanup }, + + { "priv_vfs_chmod_froot", priv_vfs_chmod_froot_setup, + priv_vfs_chmod_froot, priv_vfs_chmod_cleanup }, + + { "priv_vfs_chmod_fowner", priv_vfs_chmod_fowner_setup, + priv_vfs_chmod_fowner, priv_vfs_chmod_cleanup }, + + { "priv_vfs_chmod_fother", priv_vfs_chmod_fother_setup, + priv_vfs_chmod_fother, priv_vfs_chmod_cleanup }, + + { "priv_vfs_chown_uid", priv_vfs_chown_uid_setup, priv_vfs_chown_uid, + priv_vfs_chown_cleanup }, + + { "priv_vfs_chown_mygid", priv_vfs_chown_mygid_setup, + priv_vfs_chown_mygid, priv_vfs_chown_cleanup }, + + { "priv_vfs_chown_othergid", priv_vfs_chown_othergid_setup, + priv_vfs_chown_othergid, priv_vfs_chown_cleanup }, + + { "priv_vfs_chroot", priv_vfs_chroot_setup, priv_vfs_chroot, + priv_vfs_chroot_cleanup }, + + { "priv_vfs_clearsugid_chgrp", priv_vfs_clearsugid_setup, + priv_vfs_clearsugid_chgrp, priv_vfs_clearsugid_cleanup }, + + { "priv_vfs_clearsugid_extattr", priv_vfs_clearsugid_setup, + priv_vfs_clearsugid_extattr, priv_vfs_clearsugid_cleanup }, + + { "priv_vfs_clearsugid_write", priv_vfs_clearsugid_setup, + priv_vfs_clearsugid_write, priv_vfs_clearsugid_cleanup }, + + { "priv_vfs_extattr_system", priv_vfs_extattr_system_setup, + priv_vfs_extattr_system, priv_vfs_extattr_system_cleanup }, + + { "priv_vfs_fhopen", priv_vfs_fhopen_setup, priv_vfs_fhopen, + priv_vfs_fhopen_cleanup }, + + { "priv_vfs_fhstat", priv_vfs_fhstat_setup, priv_vfs_fhstat, + priv_vfs_fhstat_cleanup }, + + { "priv_vfs_fhstatfs", priv_vfs_fhstatfs_setup, priv_vfs_fhstatfs, + priv_vfs_fhstatfs_cleanup }, + + { "priv_vfs_generation", priv_vfs_generation_setup, + priv_vfs_generation, priv_vfs_generation_cleanup }, + + { "priv_vfs_getfh", priv_vfs_getfh_setup, priv_vfs_getfh, + priv_vfs_getfh_cleanup }, + + { "priv_vfs_readwrite_fowner", priv_vfs_readwrite_fowner_setup, + priv_vfs_readwrite_fowner, priv_vfs_readwrite_cleanup }, + + { "priv_vfs_readwrite_fgroup", priv_vfs_readwrite_fgroup_setup, + priv_vfs_readwrite_fgroup, priv_vfs_readwrite_cleanup }, + + { "priv_vfs_readwrite_fother", priv_vfs_readwrite_fother_setup, + priv_vfs_readwrite_fother, priv_vfs_readwrite_cleanup }, + + { "priv_vfs_setgid_fowner", priv_vfs_setgid_fowner_setup, + priv_vfs_setgid_fowner, priv_vfs_setgid_cleanup }, + + { "priv_vfs_setgid_fother", priv_vfs_setgid_fother_setup, + priv_vfs_setgid_fother, priv_vfs_setgid_cleanup }, + + { "priv_vfs_stickyfile_dir_fowner", + priv_vfs_stickyfile_dir_fowner_setup, + priv_vfs_stickyfile_dir_fowner, + priv_vfs_stickyfile_dir_cleanup }, + + { "priv_vfs_stickyfile_dir_fother", + priv_vfs_stickyfile_dir_fother_setup, + priv_vfs_stickyfile_dir_fother, + priv_vfs_stickyfile_dir_cleanup }, + + { "priv_vfs_stickyfile_file_fowner", + priv_vfs_stickyfile_file_fowner_setup, + priv_vfs_stickyfile_file_fowner, + priv_vfs_stickyfile_file_cleanup }, + + { "priv_vfs_stickyfile_file_fother", + priv_vfs_stickyfile_file_fother_setup, + priv_vfs_stickyfile_file_fother, + priv_vfs_stickyfile_file_cleanup }, + + { "priv_vfs_utimes_froot", priv_vfs_utimes_froot_setup, + priv_vfs_utimes_froot, priv_vfs_utimes_cleanup }, + + { "priv_vfs_utimes_froot_null", priv_vfs_utimes_froot_setup, + priv_vfs_utimes_froot_null, priv_vfs_utimes_cleanup }, + + { "priv_vfs_utimes_fowner", priv_vfs_utimes_fowner_setup, + priv_vfs_utimes_fowner, priv_vfs_utimes_cleanup }, + + { "priv_vfs_utimes_fowner_null", priv_vfs_utimes_fowner_setup, + priv_vfs_utimes_fowner_null, priv_vfs_utimes_cleanup }, + + { "priv_vfs_utimes_fother", priv_vfs_utimes_fother_setup, + priv_vfs_utimes_fother, priv_vfs_utimes_cleanup }, + + { "priv_vfs_utimes_fother_null", priv_vfs_utimes_fother_setup, + priv_vfs_utimes_fother_null, priv_vfs_utimes_cleanup }, + + { "priv_vm_madv_protect", priv_vm_madv_protect_setup, + priv_vm_madv_protect, priv_vm_madv_protect_cleanup }, + + { "priv_vm_mlock", priv_vm_mlock_setup, priv_vm_mlock, + priv_vm_mlock_cleanup }, + + { "priv_vm_munlock", priv_vm_munlock_setup, priv_vm_munlock, + priv_vm_munlock_cleanup }, + +}; +static int tests_count = sizeof(tests) / sizeof(struct test); + +void +expect(const char *test, int error, int expected_error, int expected_errno) +{ + + if (error == 0) { + if (expected_error != 0) + warnx("%s: returned 0", test); + } else { + if (expected_error == 0) + warn("%s: returned (%d, %d)", test, error, errno); + else if (expected_errno != errno) + warn("%s: returned (%d, %d)", test, error, errno); + } +} + void -assert_root(void) +setup_dir(const char *test, char *dpathp, uid_t uid, gid_t gid, mode_t mode) { - if (getuid() != UID_ROOT || geteuid() != UID_ROOT) - err(-1, "must be run as root"); + strcpy(dpathp, "/tmp/priv.XXXXXXXXXXX"); + if (mkdtemp(dpathp) == NULL) + err(-1, "test %s: mkdtemp", test); + + if (chown(dpathp, uid, gid) < 0) + err(-1, "test %s: chown(%s, %d, %d)", test, dpathp, uid, + gid); + + if (chmod(dpathp, mode) < 0) + err(-1, "test %s: chmod(%s, 0%o)", test, dpathp, mode); } void -setup_file(char *fpathp, uid_t uid, gid_t gid, mode_t mode) +setup_file(const char *test, char *fpathp, uid_t uid, gid_t gid, mode_t mode) { int fd; strcpy(fpathp, "/tmp/priv.XXXXXXXXXXX"); fd = mkstemp(fpathp); if (fd < 0) - err(-1, "mkstemp"); + err(-1, "test %s: mkstemp", test); if (fchown(fd, uid, gid) < 0) - err(-1, "fchown(%s, %d, %d)", fpathp, uid, gid); + err(-1, "test %s: fchown(%s, %d, %d)", test, fpathp, uid, + gid); if (fchmod(fd, mode) < 0) - err(-1, "chmod(%s, 0%o)", fpathp, mode); + err(-1, "test %s: chmod(%s, 0%o)", test, fpathp, mode); close(fd); } /* - * When downgrading privileges, set the gid before the uid; when upgrading, - * set uid before gid. + * Irrevocably set credentials to specific uid and gid. */ -void -set_creds(uid_t uid, gid_t gid) +static void +set_creds(const char *test, uid_t uid, gid_t gid) { + gid_t gids[1] = { gid }; - if (setegid(gid) < 0) - err(-1, "setegid(%d)", gid); - if (seteuid(uid) < 0) - err(-1, "seteuid(%d)", uid); + if (setgid(gid) < 0) + err(-1, "test %s: setegid(%d)", test, gid); + if (setgroups(sizeof(gids)/sizeof(gid_t), gids) < 0) + err(-1, "test %s: setgroups(%d)", test, gid); + if (setuid(uid) < 0) + err(-1, "test %s: seteuid(%d)", test, uid); } -void -set_euid(uid_t uid) +static void +enter_jail(const char *test) { + struct jail j; - if (seteuid(uid) < 0) - err(-1, "seteuid(%d)", uid); + bzero(&j, sizeof(j)); + j.version = 0; + j.path = "/"; + j.hostname = "test"; + j.ip_number = htonl(INADDR_LOOPBACK); + if (jail(&j) < 0) + err(-1, "test %s: jail", test); } -void -restore_creds(void) +static void +run_child(struct test *test, int asroot, int injail) { - if (seteuid(UID_ROOT) < 0) - err(-1, "seteuid(%d)", UID_ROOT); - if (setegid(GID_WHEEL) < 0) - err(-1, "setegid(%d)", GID_WHEEL); + setprogname(test->t_name); + if (injail) + enter_jail(test->t_name); + if (!asroot) + set_creds(test->t_name, UID_OWNER, GID_OWNER); + test->t_test_func(asroot, injail, test); } /* - * Execute tests in a child process so they don't contaminate each other, - * especially with regard to file descriptors, credentials, working - * directories, and chroot status. + * Run a test in a particular credential context -- always call the setup and + * cleanup routines; if setup succeeds, also run the test. Test cleanup must + * handle cases where the setup has failed, so may need to maintain their own + * state in order to know what needs cleaning up (such as whether temporary + * files were created). */ static void -run(const char *funcname, void (*func)(void)) +run(struct test *test, int asroot, int injail) { pid_t childpid, pid; - printf("running %s\n", funcname); + if (test->t_setup_func != NULL) { + if ((test->t_setup_func)(asroot, injail, test) != 0) { + warnx("run(%s, %d, %d) setup failed", test->t_name, + asroot, injail); + goto cleanup; + } + } fflush(stdout); fflush(stderr); childpid = fork(); - if (childpid == -1) - err(-1, "test %s unable to fork", funcname); + if (childpid == -1) { + warn("run(%s, %d, %d) fork failed", test->t_name, asroot, + injail); + goto cleanup; + } if (childpid == 0) { - setprogname(funcname); - func(); + run_child(test, asroot, injail); fflush(stdout); fflush(stderr); exit(0); @@ -135,50 +456,42 @@ run(const char *funcname, void (*func)(void)) while (1) { pid = waitpid(childpid, NULL, 0); if (pid == -1) - warn("waitpid %s", funcname); + warn("test: waitpid %s", test->t_name); if (pid == childpid) break; } } fflush(stdout); fflush(stderr); +cleanup: + if (test->t_cleanup_func != NULL) + test->t_cleanup_func(asroot, injail, test); } int main(int argc, char *argv[]) { + int i; - run("priv_acct", priv_acct); - run("priv_adjtime", priv_adjtime); - run("priv_clock_settime", priv_clock_settime); - run("priv_io", priv_io); - run("priv_kenv_set", priv_kenv_set); - run("priv_kenv_unset", priv_kenv_unset); - run("priv_proc_setlogin", priv_proc_setlogin); - run("priv_proc_setrlimit", priv_proc_setrlimit); - run("priv_sched_rtprio", priv_sched_rtprio); - run("priv_sched_setpriority", priv_sched_setpriority); - run("priv_settimeofday", priv_settimeofday); - run("priv_sysctl_write", priv_sysctl_write); - run("priv_vfs_admin", priv_vfs_admin); - run("priv_vfs_chown", priv_vfs_chown); - run("priv_vfs_chroot", priv_vfs_chroot); - run("priv_vfs_clearsugid", priv_vfs_clearsugid); - run("priv_vfs_extattr_system", priv_vfs_extattr_system); - run("priv_vfs_fhopen", priv_vfs_fhopen); - run("priv_vfs_fhstat", priv_vfs_fhstat); - run("priv_vfs_fhstatfs", priv_vfs_fhstatfs); - run("priv_vfs_generation", priv_vfs_generation); - run("priv_vfs_getfh", priv_vfs_getfh); - run("priv_vfs_read", priv_vfs_read); - run("priv_vfs_setgid", priv_vfs_setgid); - run("priv_vfs_stickyfile", priv_vfs_stickyfile); - run("priv_vfs_write", priv_vfs_write); - run("priv_vm_madv_protect", priv_vm_madv_protect); - run("priv_vm_mlock", priv_vm_mlock); - run("priv_vm_munlock", priv_vm_munlock); - - run("test_utimes", test_utimes); + /* + * This test suite will need to become quite a bit more enlightened + * if the notion of privilege is truly separated from root, as tests + * make assumptions about when privilege will be present. In + * particular, VFS-related tests need to manage uids in order to + * force the use of privilege, and will likely need checking. + */ + if (getuid() != 0 && geteuid() != 0) + errx(-1, "priv: must be run as root"); + /* + * Run each test four times, varying whether the process is running + * as root and in jail in order to test all possible combinations. + */ + for (i = 0; i < tests_count; i++) { + run(&tests[i], 0, 0); + run(&tests[i], 0, 1); + run(&tests[i], 1, 0); + run(&tests[i], 1, 1); + } return (0); } diff --git a/tools/regression/priv/main.h b/tools/regression/priv/main.h index 6c5616b..d863feb 100644 --- a/tools/regression/priv/main.h +++ b/tools/regression/priv/main.h @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -40,51 +41,273 @@ #define KENV_VAR_NAME "test" #define KENV_VAR_VALUE "test" +#define KENV_VAR_LEN sizeof(KENV_VAR_VALUE) /* * Library routines used by many tests. */ -void assert_root(void); -void setup_file(char *fpathp, uid_t uid, gid_t gid, mode_t mode); -void set_creds(uid_t uid, gid_t gid); -void set_euid(uid_t uid); -void restore_creds(void); +void setup_dir(const char *test, char *dpathp, uid_t uid, gid_t gid, + mode_t mode); +void setup_file(const char *test, char *fpathp, uid_t uid, gid_t gid, + mode_t mode); +void expect(const char *test, int error, int expected_error, + int expected_errno); /* - * Tests for specific privileges. + * Definition for a particular test, both used to manage the test list in + * main.c, and passed to tests so they can be aware of which specific test is + * running if particular method implementations are shared across tests. */ -void priv_acct(void); -void priv_adjtime(void); -void priv_clock_settime(void); -void priv_io(void); -void priv_kenv_set(void); -void priv_kenv_unset(void); -void priv_proc_setlogin(void); -void priv_proc_setrlimit(void); -void priv_sched_rtprio(void); -void priv_sched_setpriority(void); -void priv_settimeofday(void); -void priv_sysctl_write(void); -void priv_vfs_admin(void); -void priv_vfs_chown(void); -void priv_vfs_chroot(void); -void priv_vfs_clearsugid(void); -void priv_vfs_extattr_system(void); -void priv_vfs_fhopen(void); -void priv_vfs_fhstat(void); -void priv_vfs_fhstatfs(void); -void priv_vfs_generation(void); -void priv_vfs_getfh(void); -void priv_vfs_read(void); -void priv_vfs_setgid(void); -void priv_vfs_stickyfile(void); -void priv_vfs_write(void); -void priv_vm_madv_protect(void); -void priv_vm_mlock(void); -void priv_vm_munlock(void); +struct test { + const char *t_name; + int (*t_setup_func)(int asroot, int injail, + struct test *test); + void (*t_test_func)(int asroot, int injail, + struct test *test); + void (*t_cleanup_func)(int asroot, int injail, + struct test *test); +}; /* - * Tests for more complex access control logic involving more than one - * privilege, or privilege combined with DAC. + * Prototypes for test functions that will be hooked up to the test vector in + * main.c. It's possible to imagine more dynamic (convenient?) ways to do + * this. */ -void test_utimes(void); +int priv_acct_setup(int, int, struct test *); +void priv_acct_enable(int, int, struct test *); +void priv_acct_disable(int, int, struct test *); +void priv_acct_rotate(int, int, struct test *); +void priv_acct_noopdisable(int, int, struct test *); +void priv_acct_cleanup(int, int, struct test *); + +int priv_adjtime_setup(int, int, struct test *); +void priv_adjtime_set(int, int, struct test *); +void priv_adjtime_cleanup(int, int, struct test *); + +int priv_audit_submit_setup(int, int, struct test *); +void priv_audit_submit(int, int, struct test *); +void priv_audit_submit_cleanup(int, int, struct test *); + +int priv_audit_control_setup(int, int, struct test *); +void priv_audit_control(int, int, struct test *); +void priv_audit_control_cleanup(int, int, struct test *); + +int priv_audit_getaudit_setup(int, int, struct test *); +void priv_audit_getaudit(int, int, struct test *); +void priv_audit_getaudit_addr(int, int, struct test *); +void priv_audit_getaudit_cleanup(int, int, struct test *); + +int priv_audit_setaudit_setup(int, int, struct test *); +void priv_audit_setaudit(int, int, struct test *); +void priv_audit_setaudit_addr(int, int, struct test *); +void priv_audit_setaudit_cleanup(int, int, struct test *); + +int priv_clock_settime_setup(int, int, struct test *); +void priv_clock_settime(int, int, struct test *); +void priv_clock_settime_cleanup(int, int, struct test *); + +int priv_cred_setup(int, int, struct test *); +void priv_cred_setuid(int, int, struct test *); +void priv_cred_seteuid(int, int, struct test *); +void priv_cred_setgid(int, int, struct test *); +void priv_cred_setegid(int, int, struct test *); +void priv_cred_setgroups(int, int, struct test *); +void priv_cred_setreuid(int, int, struct test *); +void priv_cred_setregid(int, int, struct test *); +void priv_cred_setresuid(int, int, struct test *); +void priv_cred_setresgid(int, int, struct test *); +void priv_cred_cleanup(int, int, struct test *); + +int priv_io_setup(int, int, struct test *); +void priv_io(int, int, struct test *); +void priv_io_cleanup(int, int, struct test *); + +int priv_kenv_set_setup(int, int, struct test *); +void priv_kenv_set(int, int, struct test *); +void priv_kenv_set_cleanup(int, int, struct test *); + +int priv_kenv_unset_setup(int, int, struct test *); +void priv_kenv_unset(int, int, struct test *); +void priv_kenv_unset_cleanup(int, int, struct test *); + +int priv_msgbuf_privonly_setup(int, int, struct test *); +void priv_msgbuf_privonly(int, int, struct test *); + +int priv_msgbuf_unprivok_setup(int, int, struct test *); +void priv_msgbuf_unprivok(int, int, struct test *); + +void priv_msgbuf_cleanup(int, int, struct test *); + +int priv_netinet_raw_setup(int, int, struct test *); +void priv_netinet_raw(int, int, struct test *); +void priv_netinet_raw_cleanup(int, int, struct test *); + +int priv_proc_setlogin_setup(int, int, struct test *); +void priv_proc_setlogin(int, int, struct test *); +void priv_proc_setlogin_cleanup(int, int, struct test *); + +int priv_proc_setrlimit_setup(int, int, struct test *); +void priv_proc_setrlimit_raisemax(int, int, struct test *); +void priv_proc_setrlimit_raisecur(int, int, struct test *); +void priv_proc_setrlimit_raisecur_nopriv(int, int, struct test *); +void priv_proc_setrlimit_cleanup(int, int, struct test *); + +int priv_sched_rtprio_setup(int, int, struct test *); +void priv_sched_rtprio_curproc_normal(int, int, struct test *); +void priv_sched_rtprio_curproc_idle(int, int, struct test *); +void priv_sched_rtprio_curproc_realtime(int, int, struct test *); + +void priv_sched_rtprio_myproc_normal(int, int, struct test *); +void priv_sched_rtprio_myproc_idle(int, int, struct test *); +void priv_sched_rtprio_myproc_realtime(int, int, struct test *); + +void priv_sched_rtprio_aproc_normal(int, int, struct test *); +void priv_sched_rtprio_aproc_idle(int, int, struct test *); +void priv_sched_rtprio_aproc_realtime(int, int, struct test *); +void priv_sched_rtprio_cleanup(int, int, struct test *); + +int priv_sched_setpriority_setup(int, int, struct test *); +void priv_sched_setpriority_curproc(int, int, struct test *); +void priv_sched_setpriority_myproc(int, int, struct test *); +void priv_sched_setpriority_aproc(int, int, struct test *); +void priv_sched_setpriority_cleanup(int, int, struct test *); + +int priv_settimeofday_setup(int, int, struct test *); +void priv_settimeofday(int, int, struct test *); +void priv_settimeofday_cleanup(int, int, struct test *); + +int priv_sysctl_write_setup(int, int, struct test *); +void priv_sysctl_write(int, int, struct test *); +void priv_sysctl_writejail(int, int, struct test *); +void priv_sysctl_write_cleanup(int, int, struct test *); + +int priv_vfs_chflags_froot_setup(int, int, struct test *); +void priv_vfs_chflags_froot_uflags(int, int, struct test *); +void priv_vfs_chflags_froot_sflags(int, int, struct test *); + +int priv_vfs_chflags_fowner_setup(int, int, struct test *); +void priv_vfs_chflags_fowner_uflags(int, int, struct test *); +void priv_vfs_chflags_fowner_sflags(int, int, struct test *); + +int priv_vfs_chflags_fother_setup(int, int, struct test *); +void priv_vfs_chflags_fother_uflags(int, int, struct test *); +void priv_vfs_chflags_fother_sflags(int, int, struct test *); + +void priv_vfs_chflags_cleanup(int, int, struct test *); + +int priv_vfs_chmod_froot_setup(int, int, struct test *); +void priv_vfs_chmod_froot(int, int, struct test *); + +int priv_vfs_chmod_fowner_setup(int, int, struct test *); +void priv_vfs_chmod_fowner(int, int, struct test *); + +int priv_vfs_chmod_fother_setup(int, int, struct test *); +void priv_vfs_chmod_fother(int, int, struct test *); + +void priv_vfs_chmod_cleanup(int, int, struct test *); + +int priv_vfs_chown_uid_setup(int, int, struct test *); +void priv_vfs_chown_uid(int, int, struct test *); + +int priv_vfs_chown_mygid_setup(int, int, struct test *); +void priv_vfs_chown_mygid(int, int, struct test *); + +int priv_vfs_chown_othergid_setup(int, int, struct test *); +void priv_vfs_chown_othergid(int, int, struct test *); + +void priv_vfs_chown_cleanup(int, int, struct test *); + +int priv_vfs_chroot_setup(int, int, struct test *); +void priv_vfs_chroot(int, int, struct test *); +void priv_vfs_chroot_cleanup(int, int, struct test *); + +int priv_vfs_clearsugid_setup(int, int, struct test *); +void priv_vfs_clearsugid_chgrp(int, int, struct test *); +void priv_vfs_clearsugid_extattr(int, int, struct test *); +void priv_vfs_clearsugid_write(int, int, struct test *); +void priv_vfs_clearsugid_cleanup(int, int, struct test *); + +int priv_vfs_extattr_system_setup(int, int, struct test *); +void priv_vfs_extattr_system(int, int, struct test *); +void priv_vfs_extattr_system_cleanup(int, int, struct test *); + +int priv_vfs_fhopen_setup(int, int, struct test *); +void priv_vfs_fhopen(int, int, struct test *); +void priv_vfs_fhopen_cleanup(int, int, struct test *); + +int priv_vfs_fhstat_setup(int, int, struct test *); +void priv_vfs_fhstat(int, int, struct test *); +void priv_vfs_fhstat_cleanup(int, int, struct test *); + +int priv_vfs_fhstatfs_setup(int, int, struct test *); +void priv_vfs_fhstatfs(int, int, struct test *); +void priv_vfs_fhstatfs_cleanup(int, int, struct test *); + +int priv_vfs_generation_setup(int, int, struct test *); +void priv_vfs_generation(int, int, struct test *); +void priv_vfs_generation_cleanup(int, int, struct test *); + +int priv_vfs_getfh_setup(int, int, struct test *); +void priv_vfs_getfh(int, int, struct test *); +void priv_vfs_getfh_cleanup(int, int, struct test *); + +int priv_vfs_readwrite_fowner_setup(int, int, struct test *); +void priv_vfs_readwrite_fowner(int, int, struct test *); + +int priv_vfs_readwrite_fgroup_setup(int, int, struct test *); +void priv_vfs_readwrite_fgroup(int, int, struct test *); + +int priv_vfs_readwrite_fother_setup(int, int, struct test *); +void priv_vfs_readwrite_fother(int, int, struct test *); + +void priv_vfs_readwrite_cleanup(int, int, struct test *); + +int priv_vfs_setgid_fowner_setup(int, int, struct test *); +void priv_vfs_setgid_fowner(int, int, struct test *); + +int priv_vfs_setgid_fother_setup(int, int, struct test *); +void priv_vfs_setgid_fother(int, int, struct test *); + +void priv_vfs_setgid_cleanup(int, int, struct test *); + +int priv_vfs_stickyfile_dir_fowner_setup(int, int, struct test *); + +void priv_vfs_stickyfile_dir_fowner(int, int, struct test *); +int priv_vfs_stickyfile_dir_fother_setup(int, int, struct test *); +void priv_vfs_stickyfile_dir_fother(int, int, struct test *); + +void priv_vfs_stickyfile_dir_cleanup(int, int, struct test *); + +int priv_vfs_stickyfile_file_fowner_setup(int, int, struct test *); +void priv_vfs_stickyfile_file_fowner(int, int, struct test *); + +int priv_vfs_stickyfile_file_fother_setup(int, int, struct test *); +void priv_vfs_stickyfile_file_fother(int, int, struct test *); + +void priv_vfs_stickyfile_file_cleanup(int, int, struct test *); + +int priv_vfs_utimes_froot_setup(int, int, struct test *); +void priv_vfs_utimes_froot(int, int, struct test *); +void priv_vfs_utimes_froot_null(int, int, struct test *); + +int priv_vfs_utimes_fowner_setup(int, int, struct test *); +void priv_vfs_utimes_fowner(int, int, struct test *); +void priv_vfs_utimes_fowner_null(int, int, struct test *); + +int priv_vfs_utimes_fother_setup(int, int, struct test *); +void priv_vfs_utimes_fother(int, int, struct test *); +void priv_vfs_utimes_fother_null(int, int, struct test *); + +void priv_vfs_utimes_cleanup(int, int, struct test *); + +int priv_vm_madv_protect_setup(int, int, struct test *); +void priv_vm_madv_protect(int, int, struct test *); +void priv_vm_madv_protect_cleanup(int, int, struct test *); + +int priv_vm_mlock_setup(int, int, struct test *); +void priv_vm_mlock(int, int, struct test *); +void priv_vm_mlock_cleanup(int, int, struct test *); + +int priv_vm_munlock_setup(int, int, struct test *); +void priv_vm_munlock(int, int, struct test *); +void priv_vm_munlock_cleanup(int, int, struct test *); diff --git a/tools/regression/priv/priv_acct.c b/tools/regression/priv/priv_acct.c index bc4a41e7..d1324bb 100644 --- a/tools/regression/priv/priv_acct.c +++ b/tools/regression/priv/priv_acct.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,11 +31,13 @@ */ /* - * Test that configuring accounting requires privilege. First check that - * accounting is not in use on the system to prevent disrupting the - * accounting service. Confirm three different state transitions, both as - * privileged and non-privileged: disabled to enabled, rotate, and enabled to - * disabled. + * Test that configuring accounting requires privilege. We test four cases + * across {!jail, jail}: + * + * priv_acct_enable - enable accounting from a disabled state + * priv_acct_disable - disable accounting from an enabled state + * priv_acct_rotate - rotate the accounting file + * priv_acct_noopdisable - disable accounting when already disabled */ #include @@ -49,130 +52,127 @@ #include "main.h" #define SYSCTL_NAME "kern.acct_configured" -#define PATH_TEMPLATE "/tmp/acct.XXXXXXXXXXX" -void -priv_acct(void) +/* + * Actual filenames used across all of the tests. + */ +static int fpath1_initialized; +static char fpath1[1024]; +static int fpath2_initialized; +static char fpath2[1024]; + +int +priv_acct_setup(int asroot, int injail, struct test *test) { - char fpath1[1024] = PATH_TEMPLATE; - char fpath2[1024] = PATH_TEMPLATE; - int error, fd, i; size_t len; + int i; - assert_root(); - - /* - * Check that accounting isn't already configured in the kernel. - */ len = sizeof(i); - if (sysctlbyname(SYSCTL_NAME, &i, &len, NULL, 0) < 0) - err(-1, "sysctlbyname(%s)", SYSCTL_NAME); - if (i != 0) - errx(-1, "sysctlbyname(%s) indicates accounting configured", + if (sysctlbyname(SYSCTL_NAME, &i, &len, NULL, 0) < 0) { + warn("priv_acct_setup: sysctlbyname(%s)", SYSCTL_NAME); + return (-1); + } + if (i != 0) { + warnx("sysctlbyname(%s) indicates accounting configured", SYSCTL_NAME); - - /* - * Create two temporary files to use as accounting targets. - */ - fd = mkstemp(fpath1); - if (fd < 0) - err(-1, "mkstemp"); - close(fd); - fd = mkstemp(fpath2); - if (fd < 0) { - warn("mkstemp"); - (void)unlink(fpath1); - exit(-1); + return (-1); } - - /* - * Change the permissions on the file so that access control on the - * file doesn't come into play. - */ - if (chmod(fpath1, 0666) < 0) { - warn("chmod(%s, 0666)", fpath1); - goto out; + setup_file("priv_acct_setup: fpath1", fpath1, 0, 0, 0666); + fpath1_initialized = 1; + setup_file("priv_acct_setup: fpath2", fpath2, 0, 0, 0666); + fpath2_initialized = 1; + + if (test->t_test_func == priv_acct_enable || + test->t_test_func == priv_acct_noopdisable) { + if (acct(NULL) != 0) { + warn("priv_acct_setup: acct(NULL)"); + return (-1); + } + } else if (test->t_test_func == priv_acct_disable || + test->t_test_func == priv_acct_rotate) { + if (acct(fpath1) != 0) { + warn("priv_acct_setup: acct(\"%s\")", fpath1); + return (-1); + } } + return (0); +} - if (chmod(fpath2, 0666) < 0) { - warn("chmod(%s, 0600)", fpath2); - goto out; - } +void +priv_acct_cleanup(int asroot, int injail, struct test *test) +{ - /* - * Test that privileged can move through entire life cycle. - */ - if (acct(fpath1) < 0) { - warn("acct(NULL -> %s) as root", fpath1); - goto out; + (void)acct(NULL); + if (fpath1_initialized) { + (void)unlink(fpath1); + fpath1_initialized = 0; } - - if (acct(fpath2) < 0) { - warn("acct(%s -> %s) as root", fpath1, fpath2); - goto out; + if (fpath2_initialized) { + (void)unlink(fpath2); + fpath2_initialized = 0; } +} - if (acct(NULL) < 0) { - warn("acct(%s -> NULL) as root", fpath1); - goto out; - } +void +priv_acct_enable(int asroot, int injail, struct test *test) +{ + int error; - /* - * Testing for unprivileged is a bit more tricky, as expect each step - * to fail, so must replay various bits of the setup process as root - * so that each step can be tested as !root. - */ - set_euid(UID_OTHER); error = acct(fpath1); - if (error == 0) { - warnx("acct(NULL -> %s) succeeded as !root", fpath1); - goto out; - } - if (errno != EPERM) { - warn("acct(NULL -> %s) wrong errno %d as !root", fpath1, - errno); - goto out; - } + if (asroot && injail) + expect("priv_acct_enable(root, jail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_acct_enable(root, !jail)", error, 0, 0); + if (!asroot && injail) + expect("priv_acct_enable(!root, jail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_acct_enable(!root, !jail)", error, -1, EPERM); +} - set_euid(UID_ROOT); - if (acct(fpath1) < 0) { - err(-1, "acct(NULL -> %s) setup for !root", fpath1); - goto out; - } +void +priv_acct_disable(int asroot, int injail, struct test *test) +{ + int error; + + error = acct(NULL); + if (asroot && injail) + expect("priv_acct_disable(root, jail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_acct_disable(root, !jail)", error, 0, 0); + if (!asroot && injail) + expect("priv_acct_disable(!root, jail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_acct_disable(!root, !jail)", error, -1, EPERM); +} + +void +priv_acct_rotate(int asroot, int injail, struct test *test) +{ + int error; - set_euid(UID_OTHER); error = acct(fpath2); - if (error == 0) { - warnx("acct(%s -> %s) succeeded as !root", fpath1, fpath2); - goto out; - } - if (errno != EPERM) { - warn("acct(%s -> %s) wrong errno %d as !root", fpath1, - fpath2, errno); - goto out; - } + if (asroot && injail) + expect("priv_acct_rotate(root, jail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_acct_rotate(root, !jail)", error, 0, 0); + if (!asroot && injail) + expect("priv_acct_rotate(!root, jail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_acct_rotate(!root, !jail)", error, -1, EPERM); +} - set_euid(UID_ROOT); - if (acct(fpath2) < 0) { - err(-1, "acct(%s -> %s) setup for !root", fpath1, fpath2); - goto out; - } +void +priv_acct_noopdisable(int asroot, int injail, struct test *test) +{ + int error; - set_euid(UID_OTHER); error = acct(NULL); - if (error == 0) { - warnx("acct(%s -> NULL) succeeded as !root", fpath2); - goto out; - } - if (errno != EPERM) { - warn("acct(%s -> NULL) wrong errno %d as !root", fpath2, - errno); - goto out; - } - -out: - (void)seteuid(UID_ROOT); - (void)acct(NULL); - (void)unlink(fpath1); - (void)unlink(fpath2); + if (asroot && injail) + expect("priv_acct_noopdisable(root, jail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_acct_noopdisable(root, !jail)", error, 0, 0); + if (!asroot && injail) + expect("priv_acct_noopdisable(!root, jail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_acct_noopdisable(!root, !jail)", error, -1, EPERM); } diff --git a/tools/regression/priv/priv_adjtime.c b/tools/regression/priv/priv_adjtime.c index 791de97..65fbfac 100644 --- a/tools/regression/priv/priv_adjtime.c +++ b/tools/regression/priv/priv_adjtime.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -31,7 +32,8 @@ /* * Confirm that privilege is required to invoke adjtime(); first query, then - * try setting first with, and then without privilege. + * try setting with and without privilege. Hopefully this will not disturb + * system time too much. */ #include @@ -42,34 +44,41 @@ #include "main.h" -void -priv_adjtime(void) +static int initialized; +static struct timeval query_tv; + +int +priv_adjtime_setup(int asroot, int injail, struct test *test) { - struct timeval tv; - int error; - assert_root(); + if (initialized) + return (0); + if (adjtime(NULL, &query_tv) < 0) { + warn("priv_adjtime_setup: adjtime(NULL)"); + return (-1); + } + initialized = 1; + return (0); +} - /* - * Query time adjustment. - */ - if (adjtime(NULL, &tv) < 0) - err(-1, "adjtime"); +void +priv_adjtime_set(int asroot, int injail, struct test *test) +{ + int error; - /* - * Set with privilege. - */ - if (adjtime(&tv, NULL) < 0) - err(-1, "adjtime as root"); + error = adjtime(&query_tv, NULL); + if (asroot && injail) + expect("priv_adjtime(asroot, injail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_adjtime(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_adjtime(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_adjtime(!asroot, !injail)", error, -1, EPERM); +} - /* - * Set without privilege. - */ - set_euid(UID_OTHER); +void +priv_adjtime_cleanup(int asroot, int injail, struct test *test) +{ - error = adjtime(&tv, NULL); - if (error == 0) - errx(-1, "adjtime succeeded as !root"); - if (errno != EPERM) - errx(-1, "adjtime wrong errno %d as !root", errno); } diff --git a/tools/regression/priv/priv_audit_control.c b/tools/regression/priv/priv_audit_control.c new file mode 100644 index 0000000..a661819 --- /dev/null +++ b/tools/regression/priv/priv_audit_control.c @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 2007 Robert M. M. Watson + * All rights reserved. + * + * This software was developed by Robert N. M. Watson for the TrustedBSD + * Project. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, + * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Confirm that privilege is required to issue an audit control command via + * auditon(). We do a simple policy retrieve. + * + * XXXRW: It would be a good idea to also test auditctl(), which also tests + * PRIV_AUDIT_CONTROL. + */ + +#include + +#include + +#include +#include +#include + +#include "main.h" + +int +priv_audit_control_setup(int asroot, int injail, struct test *test) +{ + + /* + * XXXRW: It would be nice if we checked for audit being configured + * here. + */ + return (0); +} + +void +priv_audit_control(int asroot, int injail, struct test *test) +{ + long policy; + int error; + + error = auditon(A_GETPOLICY, &policy, sizeof(policy)); + if (asroot && injail) + expect("priv_audit_control(asroot, injail)", error, -1, + ENOSYS); + if (asroot && !injail) + expect("priv_audit_control(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_audit_control(!asroot, injail)", error, -1, + ENOSYS); + if (!asroot && !injail) + expect("priv_audit_control(!asroot, !injail)", error, -1, + EPERM); +} + +void +priv_audit_control_cleanup(int asroot, int injail, struct test *test) +{ + +} diff --git a/tools/regression/priv/priv_audit_getaudit.c b/tools/regression/priv/priv_audit_getaudit.c new file mode 100644 index 0000000..cccabed --- /dev/null +++ b/tools/regression/priv/priv_audit_getaudit.c @@ -0,0 +1,102 @@ +/*- + * Copyright (c) 2007 Robert M. M. Watson + * All rights reserved. + * + * This software was developed by Robert N. M. Watson for the TrustedBSD + * Project. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, + * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Confirm that privilege is required to query process audit state. + */ + +#include + +#include + +#include +#include +#include + +#include "main.h" + +int +priv_audit_getaudit_setup(int asroot, int injail, struct test *test) +{ + + /* + * XXXRW: It would be nice if we checked for audit being configured + * here. + */ + return (0); +} + +void +priv_audit_getaudit(int asroot, int injail, struct test *test) +{ + auditinfo_t ai; + int error; + + error = getaudit(&ai); + if (asroot && injail) + expect("priv_audit_getaudit(asroot, injail)", error, -1, + ENOSYS); + if (asroot && !injail) + expect("priv_audit_getaudit(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_audit_getaudit(!asroot, injail)", error, -1, + ENOSYS); + if (!asroot && !injail) + expect("priv_audit_getaudit(!asroot, !injail)", error, -1, + EPERM); +} + +void +priv_audit_getaudit_addr(int asroot, int injail, struct test *test) +{ + auditinfo_addr_t aia; + int error; + + error = getaudit_addr(&aia, sizeof(aia)); + if (asroot && injail) + expect("priv_audit_getaudit_addr(asroot, injail)", error, -1, + ENOSYS); + if (asroot && !injail) + expect("priv_audit_getaudit_addr(asroot, !injail)", error, 0, + 0); + if (!asroot && injail) + expect("priv_audit_getaudit_addr(!asroot, injail)", error, + -1, ENOSYS); + if (!asroot && !injail) + expect("priv_audit_getaudit_addr(!asroot, !injail)", error, + -1, EPERM); +} + +void +priv_audit_getaudit_cleanup(int asroot, int injail, struct test *test) +{ + +} diff --git a/tools/regression/priv/priv_audit_setaudit.c b/tools/regression/priv/priv_audit_setaudit.c new file mode 100644 index 0000000..0b6d8db --- /dev/null +++ b/tools/regression/priv/priv_audit_setaudit.c @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2007 Robert M. M. Watson + * All rights reserved. + * + * This software was developed by Robert N. M. Watson for the TrustedBSD + * Project. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, + * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Confirm privilege is required to set process audit properties; we first + * query current properties so that the attempted operation is a no-op. + */ + +#include + +#include + +#include +#include +#include + +#include "main.h" + +static auditinfo_t ai; +static auditinfo_addr_t aia; + +int +priv_audit_setaudit_setup(int asroot, int injail, struct test *test) +{ + + if (getaudit(&ai) < 0) { + warn("priv_audit_setaudit_setup: getaudit"); + return (-1); + } + if (getaudit_addr(&aia, sizeof(aia)) < 0) { + warn("priv_audit_setaudit_setup: getaudit_addr"); + return (-1); + } + + return (0); +} + +void +priv_audit_setaudit(int asroot, int injail, struct test *test) +{ + int error; + + error = setaudit(&ai); + if (asroot && injail) + expect("priv_audit_setaudit(asroot, injail)", error, -1, + ENOSYS); + if (asroot && !injail) + expect("priv_audit_setaudit(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_audit_setaudit(!asroot, injail)", error, -1, + ENOSYS); + if (!asroot && !injail) + expect("priv_audit_setaudit(!asroot, !injail)", error, -1, + EPERM); +} + +void +priv_audit_setaudit_addr(int asroot, int injail, struct test *test) +{ + int error; + + error = setaudit_addr(&aia, sizeof(aia)); + if (asroot && injail) + expect("priv_audit_setaudit_addr(asroot, injail)", error, -1, + ENOSYS); + if (asroot && !injail) + expect("priv_audit_setaudit_addr(asroot, !injail)", error, 0, + 0); + if (!asroot && injail) + expect("priv_audit_setaudit_addr(!asroot, injail)", error, + -1, ENOSYS); + if (!asroot && !injail) + expect("priv_audit_setaudit_addr(!asroot, !injail)", error, + -1, EPERM); +} + +void +priv_audit_setaudit_cleanup(int asroot, int injail, struct test *test) +{ + +} diff --git a/tools/regression/priv/priv_audit_submit.c b/tools/regression/priv/priv_audit_submit.c new file mode 100644 index 0000000..915f6e6 --- /dev/null +++ b/tools/regression/priv/priv_audit_submit.c @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2007 Robert M. M. Watson + * All rights reserved. + * + * This software was developed by Robert N. M. Watson for the TrustedBSD + * Project. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, + * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Confirm that privilege is required to submit an audit record; we don't + * actually submit a record, but instead rely on the fact that length + * validation of the record will occur after the kernel privilege check. + * + * XXX: It might be better to submit a nul record of some sort. + */ + +#include + +#include + +#include +#include +#include +#include + +#include "main.h" + +int +priv_audit_submit_setup(int asroot, int injail, struct test *test) +{ + + /* + * XXXRW: It would be nice if we checked for audit being configured + * here. + */ + return (0); +} + +void +priv_audit_submit(int asroot, int injail, struct test *test) +{ + char record[MAX_AUDIT_RECORD_SIZE+10]; + int error; + + bzero(record, sizeof(record)); + error = audit(record, sizeof(record)); + if (asroot && injail) + expect("priv_audit_submit(asroot, injail)", error, -1, + ENOSYS); + if (asroot && !injail) + expect("priv_audit_submit(asroot, !injail)", error, -1, + EINVAL); + if (!asroot && injail) + expect("priv_audit_submit(!asroot, injail)", error, -1, + ENOSYS); + if (!asroot && !injail) + expect("priv_audit_submit(!asroot, !injail)", error, -1, + EPERM); +} + +void +priv_audit_submit_cleanup(int asroot, int injail, struct test *test) +{ + +} diff --git a/tools/regression/priv/priv_clock_settime.c b/tools/regression/priv/priv_clock_settime.c index e3d1089..84b8beb 100644 --- a/tools/regression/priv/priv_clock_settime.c +++ b/tools/regression/priv/priv_clock_settime.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -43,34 +44,41 @@ #include "main.h" -void -priv_clock_settime(void) +static struct timespec the_time; + +int +priv_clock_settime_setup(int asroot, int injail, struct test *test) { - struct timespec ts; - int error; - assert_root(); + if (clock_gettime(CLOCK_REALTIME, &the_time) < 0) { + warn("priv_clock_settime_setup: " + "clock_gettime(CLOCK_REALTIME)"); + return (-1); + } + return (0); +} - /* - * Query time. - */ - if (clock_gettime(CLOCK_REALTIME, &ts) < 0) - err(-1, "clock_gettime"); +void +priv_clock_settime(int asroot, int injail, struct test *test) +{ + int error; - /* - * Set with privilege. - */ - if (clock_settime(CLOCK_REALTIME, &ts) < 0) - err(-1, "clock_settime as root"); + error = clock_settime(CLOCK_REALTIME, &the_time); + if (asroot && injail) + expect("priv_clock_settime(asroot, injail)", error, -1, + EPERM); + if (asroot && !injail) + expect("priv_clock_settime(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_clock_settime(!asroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_clock_settime(!asroot, !injail", error, -1, + EPERM); +} - /* - * Set without privilege. - */ - set_euid(UID_OTHER); +void +priv_clock_settime_cleanup(int asroot, int injail, struct test *test) +{ - error = clock_settime(CLOCK_REALTIME, &ts); - if (error == 0) - errx(-1, "clock_settime succeeded as !root"); - if (errno != EPERM) - errx(-1, "clock_settime wrong errno %d as !root", errno); } diff --git a/tools/regression/priv/priv_cred.c b/tools/regression/priv/priv_cred.c new file mode 100644 index 0000000..6e060cf --- /dev/null +++ b/tools/regression/priv/priv_cred.c @@ -0,0 +1,208 @@ +/*- + * Copyright (c) 2007 Robert M. M. Watson + * All rights reserved. + * + * This software was developed by Robert N. M. Watson for the TrustedBSD + * Project. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, + * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Confirm that various UID/GID/etc-related system calls require root + * privilege in the absense of any saved/real/etc variations in the + * credential. It would be nice to also check cases where those bits of the + * credential are more interesting. + * + * XXXRW: Add support for testing more diverse real/saved scenarios. + */ + +#include + +#include +#include +#include +#include + +#include "main.h" + +int +priv_cred_setup(int asroot, int injail, struct test *test) +{ + + return (0); +} + +void +priv_cred_setuid(int asroot, int injail, struct test *test) +{ + int error; + + error = setuid(UID_OTHER); + if (asroot && injail) + expect("priv_setuid(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_setuid(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_setuid(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_setuid(!asroot, !injail)", error, -1, EPERM); +} + +void +priv_cred_seteuid(int asroot, int injail, struct test *test) +{ + int error; + + error = seteuid(UID_OTHER); + if (asroot && injail) + expect("priv_seteuid(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_seteuid(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_seteuid(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_seteuid(!asroot, !injail)", error, -1, EPERM); +} + +void +priv_cred_setgid(int asroot, int injail, struct test *test) +{ + int error; + + error = setgid(GID_OTHER); + if (asroot && injail) + expect("priv_setgid(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_setgid(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_setgid(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_setgid(!asroot, !injail)", error, -1, EPERM); +} + +void +priv_cred_setegid(int asroot, int injail, struct test *test) +{ + int error; + + error = setegid(GID_OTHER); + if (asroot && injail) + expect("priv_setegid(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_setegid(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_setegd(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_setegid(!asroot, !injail)", error, -1, EPERM); +} + +static const gid_t gidset[] = {GID_WHEEL, GID_OTHER}; +static const int gidset_len = sizeof(gidset) / sizeof(gid_t); + +void +priv_cred_setgroups(int asroot, int injail, struct test *test) +{ + int error; + + error = setgroups(gidset_len, gidset); + if (asroot && injail) + expect("priv_setgroups(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_setgroups(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_setgroups(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_setgroups(!asroot, !injail)", error, -1, EPERM); +} + +void +priv_cred_setreuid(int asroot, int injail, struct test *test) +{ + int error; + + error = setreuid(UID_OTHER, UID_OTHER); + if (asroot && injail) + expect("priv_setreuid(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_setreuid(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_setreuid(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_setreuid(!asroot, !injail)", error, -1, EPERM); +} + +void +priv_cred_setregid(int asroot, int injail, struct test *test) +{ + int error; + + error = setregid(GID_OTHER, GID_OTHER); + if (asroot && injail) + expect("priv_setregid(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_setregid(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_setregid(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_setregid(!asroot, !injail)", error, -1, EPERM); +} + +void +priv_cred_setresuid(int asroot, int injail, struct test *test) +{ + int error; + + error = setresuid(UID_OTHER, UID_OTHER, UID_OTHER); + if (asroot && injail) + expect("priv_setresuid(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_setresuid(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_setresuid(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_setresuid(!asroot, !injail)", error, -1, EPERM); +} + +void +priv_cred_setresgid(int asroot, int injail, struct test *test) +{ + int error; + + error = setresgid(GID_OTHER, GID_OTHER, GID_OTHER); + if (asroot && injail) + expect("priv_setresgid(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_setresgid(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_setresgid(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_setresgid(!asroot, !injail)", error, -1, EPERM); +} + +void +priv_cred_cleanup(int asroot, int injail, struct test *test) +{ + +} diff --git a/tools/regression/priv/priv_io.c b/tools/regression/priv/priv_io.c index 1af1847..31e60a0 100644 --- a/tools/regression/priv/priv_io.c +++ b/tools/regression/priv/priv_io.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -32,9 +33,8 @@ /* * Test privilege check on /dev/io. By default, the permissions also protect * against non-superuser access, so this program will modify permissions on - * /dev/io to allow group access for the wheel group, and revert the change - * on exit. This is not good for run-time security, but is necessary to test - * the checks properly. + * /dev/io to allow world access, and revert the change on exit. This is not + * good for run-time security, but is necessary to test the checks properly. */ #include @@ -47,89 +47,66 @@ #include "main.h" -#define NEW_PERMS 0660 +#define NEW_PERMS 0666 #define DEV_IO "/dev/io" #define EXPECTED_PERMS 0600 -static mode_t saved_perms; +static int initialized; +static mode_t saved_perms; -static void -save_perms(void) +int +priv_io_setup(int asroot, int asjail, struct test *test) { struct stat sb; - if (stat(DEV_IO, &sb) < 0) - err(-1, "save_perms: stat(%s)", DEV_IO); - + if (stat(DEV_IO, &sb) < 0) { + warn("priv_io_setup: stat(%s)", DEV_IO); + return (-1); + } saved_perms = sb.st_mode & ALLPERMS; - - if (saved_perms != EXPECTED_PERMS) - err(-1, "save_perms: perms = 0%o; expected 0%o", saved_perms, - EXPECTED_PERMS); - -} - -static void -set_perms(void) -{ - - if (chmod(DEV_IO, NEW_PERMS) < 0) - err(-1, "set_perms: chmod(%s, 0%o)", DEV_IO, NEW_PERMS); -} - -static void -restore_perms(void) -{ - - if (chmod(DEV_IO, saved_perms) < 0) - err(-1, "restore_perms: chmod(%s, 0%o)", DEV_IO, saved_perms); + if (saved_perms != EXPECTED_PERMS) { + warnx("priv_io_setup: perms = 0%o; expected 0%o", + saved_perms, EXPECTED_PERMS); + return (-1); + } + if (chmod(DEV_IO, NEW_PERMS) < 0) { + warn("priv_io_setup: chmod(%s, 0%o)", DEV_IO, NEW_PERMS); + return (-1); + } + initialized = 1; + return (0); } -static void -try_open(const char *test_case, uid_t uid, int expected) +void +priv_io(int asroot, int injail, struct test *test) { - int fd; + int error, fd; - set_euid(uid); fd = open(DEV_IO, O_RDONLY); - if (expected == 0) { - if (fd == -1) { - warn("try_open: %s open(%s) errno %d", DEV_IO, - test_case, errno); - goto out; - } + if (fd < 0) + error = -1; + else + error = 0; + if (asroot && injail) + expect("priv_io(asroot, injail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_io(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_io(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_io(!asroot, !injail)", error, -1, EPERM); + if (fd != -1) close(fd); - goto out; - } - if (fd >= 0) { - warn("try_open: %s open(%s) unexpected success", test_case, - DEV_IO); - close(fd); - goto out; - } - if (errno == expected) - goto out; - warn("try_open: %s open(%s) wrong errno %d, expected %d", DEV_IO, - test_case, errno, expected); -out: - set_euid(UID_ROOT); } void -priv_io(void) +priv_io_cleanup(int asroot, int asjail, struct test *test) { - assert_root(); - - save_perms(); - - try_open("root:0600", UID_ROOT, 0); - try_open("other", UID_OTHER, EACCES); - - set_perms(); - - try_open("root:0660", UID_ROOT, 0); - try_open("other", UID_OTHER, EPERM); - - restore_perms(); + if (!initialized) + return; + if (chmod(DEV_IO, saved_perms) < 0) + err(-1, "priv_io_cleanup: chmod(%s, 0%o)", DEV_IO, + saved_perms); + initialized = 0; } diff --git a/tools/regression/priv/priv_kenv_set.c b/tools/regression/priv/priv_kenv_set.c index 96e785d..1e750e0 100644 --- a/tools/regression/priv/priv_kenv_set.c +++ b/tools/regression/priv/priv_kenv_set.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,8 +31,7 @@ */ /* - * Test that setting a kernel environment variable requires privilege, by - * first trying it with privilege, then without. + * Test that setting a kernel environment variable requires privilege. */ #include @@ -44,25 +44,33 @@ #include "main.h" +int +priv_kenv_set_setup(int asroot, int injail, struct test *test) +{ + + (void)kenv(KENV_UNSET, KENV_VAR_NAME, NULL, 0); + return (0); +} + void -priv_kenv_set(void) +priv_kenv_set(int asroot, int injail, struct test *test) { int error; - assert_root(); - - error = kenv(KENV_SET, KENV_VAR_NAME, KENV_VAR_VALUE, - strlen(KENV_VAR_VALUE)+1); - if (error) - err(-1, "kenv(KENV_SET, ...) as root"); + error = kenv(KENV_SET, KENV_VAR_NAME, KENV_VAR_VALUE, KENV_VAR_LEN); + if (asroot && injail) + expect("priv_kenv_set(asroot, injail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_kenv_set(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_kenv_set(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_kenv_set(!asroot, !injail)", error, -1, EPERM); +} - set_euid(UID_OTHER); +void +priv_kenv_set_cleanup(int asroot, int injail, struct test *test) +{ - error = kenv(KENV_SET, KENV_VAR_NAME, KENV_VAR_VALUE, - strlen(KENV_VAR_VALUE)+1); - if (error == 0) - errx(-1, "kenv(KENV_SET, ...) as !root succeeded"); - if (errno != EPERM) - err(-1, "kenv(KENV_SET, ...) as !root wrong errno %d", - errno); + (void)kenv(KENV_UNSET, KENV_VAR_NAME, NULL, 0); } diff --git a/tools/regression/priv/priv_kenv_unset.c b/tools/regression/priv/priv_kenv_unset.c index 2bb800d..02004da 100644 --- a/tools/regression/priv/priv_kenv_unset.c +++ b/tools/regression/priv/priv_kenv_unset.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,8 +31,7 @@ */ /* - * Test that setting a kernel environment variable, then trying to unset it - * without and with privilege. + * Test setting a kernel environment variable, then try to unset it. */ #include @@ -44,34 +44,36 @@ #include "main.h" -void -priv_kenv_unset(void) +int +priv_kenv_unset_setup(int asroot, int injail, struct test *test) { - int error; - assert_root(); + if (kenv(KENV_SET, KENV_VAR_NAME, KENV_VAR_VALUE, KENV_VAR_LEN) < 0) { + warn("priv_kenv_unset: kenv"); + return (-1); + } + return (0); +} - error = kenv(KENV_SET, KENV_VAR_NAME, KENV_VAR_VALUE, - strlen(KENV_VAR_VALUE)+1); - if (error) - err(-1, "kenv(KENV_SET, ...) as root"); +void +priv_kenv_unset(int asroot, int injail, struct test *test) +{ + int error; error = kenv(KENV_UNSET, KENV_VAR_NAME, NULL, 0); - if (error) - err(-1, "kenv(KENV_UNSET, ...) as root"); - - /* Set it again for !root. */ - error = kenv(KENV_SET, KENV_VAR_NAME, KENV_VAR_VALUE, - strlen(KENV_VAR_VALUE)+1); - if (error) - err(-1, "kenv(KENV_SET, ...) as root"); + if (asroot && injail) + expect("priv_kenv_unset(asroot, injail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_kenv_unset(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_kenv_unset(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_kenv_unset(!asroot, !injail)", error, -1, EPERM); +} - set_euid(UID_OTHER); +void +priv_kenv_unset_cleanup(int asroot, int injail, struct test *test) +{ - error = kenv(KENV_UNSET, KENV_VAR_NAME, NULL, 0); - if (error == 0) - errx(-1, "kenv(KENV_UNSET, ...) as !root succeeded"); - if (errno != EPERM) - err(-1, "kenv(KENV_UNSET, ...) as !root wrong errno %d", - errno); + (void)kenv(KENV_UNSET, KENV_VAR_NAME, NULL, 0); } diff --git a/tools/regression/priv/priv_msgbuf.c b/tools/regression/priv/priv_msgbuf.c new file mode 100644 index 0000000..c8db210 --- /dev/null +++ b/tools/regression/priv/priv_msgbuf.c @@ -0,0 +1,152 @@ +/*- + * Copyright (c) 2007 Robert M. M. Watson + * All rights reserved. + * + * This software was developed by Robert N. M. Watson for the TrustedBSD + * Project. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, + * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Confirm that when security.bsd.unprivileged_read_msgbuf is set to 0, + * privilege is required to read the kernel message buffer. + */ + +#include +#include + +#include +#include +#include + +#include "main.h" + +#define MSGBUF_CONTROL_NAME "security.bsd.unprivileged_read_msgbuf" +#define MSGBUF_NAME "kern.msgbuf" + +/* + * We must query and save the original value, then restore it when done. + */ +static int unprivileged_read_msgbuf; +static int unprivileged_read_msgbuf_initialized; + +int +priv_msgbuf_privonly_setup(int asroot, int injail, struct test *test) +{ + size_t len; + int newval; + + /* + * Separately query and set to make debugging easier. + */ + len = sizeof(unprivileged_read_msgbuf); + if (sysctlbyname(MSGBUF_CONTROL_NAME, &unprivileged_read_msgbuf, + &len, NULL, 0) < 0) { + warn("priv_msgbuf_privonly_setup: sysctlbyname query"); + return (-1); + } + newval = 0; + if (sysctlbyname(MSGBUF_CONTROL_NAME, NULL, NULL, &newval, + sizeof(newval)) < 0) { + warn("priv_msgbuf_privonly_setup: sysctlbyname set"); + return (-1); + } + unprivileged_read_msgbuf_initialized = 1; + return (0); +} + +void +priv_msgbuf_privonly(int asroot, int injail, struct test *test) +{ + size_t len; + int error; + + error = sysctlbyname(MSGBUF_NAME, NULL, &len, NULL, 0); + if (asroot && injail) + expect("priv_msgbuf_privonly(asroot, injail)", error, -1, + EPERM); + if (asroot && !injail) + expect("priv_msgbuf_privonly(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_msgbuf_privonly(!asroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_msgbuf_privonly(!asroot, !injail)", error, -1, + EPERM); +} + +int +priv_msgbuf_unprivok_setup(int asroot, int injail, struct test *test) +{ + size_t len; + int newval; + + /* + * Separately query and set to make debugging easier. + */ + len = sizeof(unprivileged_read_msgbuf); + if (sysctlbyname(MSGBUF_CONTROL_NAME, &unprivileged_read_msgbuf, &len, + NULL, 0) < 0) { + warn("priv_msgbuf_unprivok_setup: sysctlbyname query"); + return (-1); + } + newval = 1; + if (sysctlbyname(MSGBUF_CONTROL_NAME, NULL, NULL, &newval, + sizeof(newval)) < 0) { + warn("priv_msgbuf_unprivok_setup: sysctlbyname set"); + return (-1); + } + unprivileged_read_msgbuf_initialized = 1; + return (0); +} + +void +priv_msgbuf_unprivok(int asroot, int injail, struct test *test) +{ + size_t len; + int error; + + error = sysctlbyname(MSGBUF_NAME, NULL, &len, NULL, 0); + if (asroot && injail) + expect("priv_msgbuf_unprivok(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_msgbuf_unprivok(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_msgbuf_unprivok(!asroot, injail)", error, 0, 0); + if (!asroot && !injail) + expect("priv_msgbuf_unprivok(!asroot, !injail)", error, 0, 0); +} + +void +priv_msgbuf_cleanup(int asroot, int injail, struct test *test) +{ + + if (unprivileged_read_msgbuf_initialized) { + (void)sysctlbyname(MSGBUF_NAME, NULL, NULL, + &unprivileged_read_msgbuf, + sizeof(unprivileged_read_msgbuf)); + unprivileged_read_msgbuf_initialized = 0; + } +} diff --git a/tools/regression/priv/priv_netinet_raw.c b/tools/regression/priv/priv_netinet_raw.c new file mode 100644 index 0000000..75f66c0 --- /dev/null +++ b/tools/regression/priv/priv_netinet_raw.c @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2007 Robert M. M. Watson + * All rights reserved. + * + * This software was developed by Robert N. M. Watson for the TrustedBSD + * Project. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, + * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Confirm that privilege is required to open a raw IP socket, and that this + * is not allowed in jail. + */ + +#include +#include + +#include +#include +#include +#include + +#include "main.h" + +int +priv_netinet_raw_setup(int asroot, int injail, struct test *test) +{ + + return (0); +} + +void +priv_netinet_raw(int asroot, int injail, struct test *test) +{ + int error, fd; + + fd = socket(PF_INET, SOCK_RAW, 0); + if (fd < 0) + error = -1; + else + error = 0; + if (asroot && injail) + expect("priv_netinet_raw(asroot, injail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_netinet_raw(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_netinet_raw(!asroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_netinet_raw(!asroot, !injail)", error, + -1, EPERM); + if (fd >= 0) + (void)close(fd); +} + +void +priv_netinet_raw_cleanup(int asroot, int injail, struct test *test) +{ + +} diff --git a/tools/regression/priv/priv_proc_setlogin.c b/tools/regression/priv/priv_proc_setlogin.c index 6f5e756..f04b79f 100644 --- a/tools/regression/priv/priv_proc_setlogin.c +++ b/tools/regression/priv/priv_proc_setlogin.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,44 +31,58 @@ */ /* - * Test that privilege is required to call setlogin(). Do so by first - * querying with getlogin(), then setting the result back using setlogin(), - * at first with privilege, then without. + * Test privileges for setlogin(); first query with getlogin() so that the + * result is a no-op, since it affects the entire login session. */ +#include + #include #include #include #include "main.h" -void -priv_proc_setlogin(void) -{ - char *loginname; - int error; +static int initialized; +static char *loginname; - assert_root(); +int +priv_proc_setlogin_setup(int asroot, int injail, struct test *test) +{ + if (initialized) + return (0); loginname = getlogin(); - if (loginname == NULL) - err(-1, "getlogin"); + if (loginname == NULL) { + warn("priv_proc_setlogin_setup: getlogin"); + return (-1); + } + initialized = 1; + return (0); +} + +void +priv_proc_setlogin(int asroot, int injail, struct test *test) +{ + int error; - /* - * First, with privilege. - */ error = setlogin(loginname); - if (error) - err(-1, "setlogin(%s) as root", loginname); + if (asroot && injail) + expect("priv_proc_setlogin(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_proc_setlogin(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_proc_setlogin(!sroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_proc_setlogin(!asroot, !injail)", error, -1, + EPERM); +} - /* - * Then again, without privilege. - */ - set_euid(UID_OTHER); +void +priv_proc_setlogin_cleanup(int asroot, int injail, struct test *test) +{ - error = setlogin(loginname); - if (error == 0) - errx(-1, "setlogin(%s) succeeded as !root", loginname); - if (errno != EPERM) - err(-1, "setlogin(%s) wrong errno %d", loginname, errno); + if (initialized) + (void)setlogin(loginname); } diff --git a/tools/regression/priv/priv_proc_setrlimit.c b/tools/regression/priv/priv_proc_setrlimit.c index adf471b..590f55f 100644 --- a/tools/regression/priv/priv_proc_setrlimit.c +++ b/tools/regression/priv/priv_proc_setrlimit.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -29,13 +30,13 @@ * $FreeBSD$ */ -/* +/*- * Test that raising current resource limits above hard resource limits - * requires privilege. There is one privilege check, but two conditions: - * - * - To raise the current above the maximum. + * requires privilege. We test three cases: * - * - To raise the maximum. + * - Raise the current above the maximum (privileged). + * - Raise the current to the maximum (unprivileged). + * - Raise the maximum (privileged). */ #include @@ -48,90 +49,122 @@ #include "main.h" -void -priv_proc_setrlimit(void) -{ - struct rlimit rl, rl_lower, rl_raise_max, rl_raise_cur; - int error; +static int initialized; +static struct rlimit rl_base; +static struct rlimit rl_lowered; - assert_root(); +int +priv_proc_setrlimit_setup(int asroot, int injail, struct test *test) +{ - /* - * To make sure that there is room to raise the resource limit, we - * must first lower it. Otherwise, if the resource limit is already - * at the global maximum, that complicates matters. In principle, we - * can bump into privilege failures during setup, but there's not - * much we can do about that. Keep this prototypical setting around - * as the target to restore to later. - */ - if (getrlimit(RLIMIT_DATA, &rl) < 0) - err(-1, "getrlimit(RLIMIT_DATA)"); + if (getrlimit(RLIMIT_DATA, &rl_base) < 0) { + warn("priv_proc_setrlimit_setup: getrlimit"); + return (-1); + } /* - * What to lower to before trying to raise. + * Must lower current and limit to make sure there's room to try to + * raise them during tests. Set current lower than max so we can + * raise it later also. */ - rl_lower = rl; - rl_lower.rlim_cur -= 10; - rl_lower.rlim_max = rl_lower.rlim_cur; + rl_lowered = rl_base; + rl_lowered.rlim_cur -= 20; + rl_lowered.rlim_max -= 10; + if (setrlimit(RLIMIT_DATA, &rl_lowered) < 0) { + warn("priv_proc_setrlimit_setup: setrlimit"); + return (-1); + } + initialized = 1; + return (0); +} - /* - * Raise the maximum. - */ - rl_raise_max = rl; - rl_raise_max.rlim_max += 10; +/* + * Try increasing the maximum limits on the process, which requires + * privilege. + */ +void +priv_proc_setrlimit_raisemax(int asroot, int injail, struct test *test) +{ + struct rlimit rl; + int error; - /* - * Raise the current above the maximum. - */ - rl_raise_cur = rl; - rl_raise_cur.rlim_cur += 10; + rl = rl_lowered; + rl.rlim_max = rl_base.rlim_max; + error = setrlimit(RLIMIT_DATA, &rl); + if (asroot && injail) + expect("priv_proc_setrlimit_raisemax(asroot, injail)", error, + 0, 0); + if (asroot && !injail) + expect("priv_proc_setrlimit_raisemax(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_proc_setrlimit_raisemax(!asroot, injail)", + error, -1, EPERM); + if (!asroot && !injail) + expect("priv_proc_setrlimit_raisemax(!asroot, !injail)", + error, -1, EPERM); +} - /* - * Test raising the maximum with privilege. - */ - if (setrlimit(RLIMIT_DATA, &rl_lower) < 0) - err(-1, "setrlimit(RLIMIT_DATA, lower) as root"); +/* + * Try setting the current limit to the current maximum, which is allowed + * without privilege. + */ +void +priv_proc_setrlimit_raisecur_nopriv(int asroot, int injail, + struct test *test) +{ + struct rlimit rl; + int error; - if (setrlimit(RLIMIT_DATA, &rl_raise_max) < 0) - err(-1, "setrlimit(RLIMIT_DATA, raise_max) as root"); + rl = rl_lowered; + rl.rlim_cur = rl.rlim_max; + error = setrlimit(RLIMIT_DATA, &rl); + if (asroot && injail) + expect("priv_proc_setrlimit_raiscur_nopriv(asroot, injail)", + error, 0, 0); + if (asroot && !injail) + expect("priv_proc_setrlimit_raisecur_nopriv(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_proc_setrlimit_raisecur_nopriv(!asroot, injail)", + error, 0, 0); + if (!asroot && !injail) + expect("priv_proc_setrlimit_raisecur_nopriv(!asroot, !injail)", + error, 0, 0); +} - /* - * Test raising the current above the maximum with privilege. - */ - if (setrlimit(RLIMIT_DATA, &rl_lower) < 0) - err(-1, "setrlimit(RLIMIT_DATA, lower) as root"); +/* + * Try raising the current limits above the maximum, which requires + * privilege. + */ +void +priv_proc_setrlimit_raisecur(int asroot, int injail, struct test *test) +{ + struct rlimit rl; + int error; - if (setrlimit(RLIMIT_DATA, &rl_raise_cur) < 0) - err(-1, "setrlimit(RLIMIT_DATA, raise_cur) as root"); + rl = rl_lowered; + rl.rlim_cur = rl.rlim_max + 10; + error = setrlimit(RLIMIT_DATA, &rl); + if (asroot && injail) + expect("priv_proc_setrlimit_raisecur(asroot, injail)", error, + 0, 0); + if (asroot && !injail) + expect("priv_proc_setrlimit_raisecur(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_proc_setrlimit_raisecur(!asroot, injail)", + error, -1, EPERM); + if (!asroot && !injail) + expect("priv_proc_setrlimit_raisecur(!asroot, !injail)", + error, -1, EPERM); +} - /* - * Test raising the maximum without privilege. - */ - if (setrlimit(RLIMIT_DATA, &rl_lower) < 0) - err(-1, "setrlimit(RLIMIT_DATA, lower) as root"); - - set_euid(UID_OTHER); - error = setrlimit(RLIMIT_DATA, &rl_raise_max); - if (error == 0) - errx(-1, - "setrlimit(RLIMIT_DATA, raise_max) succeeded as !root"); - if (errno != EPERM) - err(-1, "setrlimit(RLIMIT_DATA, raise_max) wrong errno %d " - "as !root", errno); +void +priv_proc_setrlimit_cleanup(int asroot, int injail, struct test *test) +{ - /* - * Test raising the current above the maximum without privilege. - */ - set_euid(UID_ROOT); - if (setrlimit(RLIMIT_DATA, &rl_lower) < 0) - err(-1, "setrlimit(RLIMIT_DATA, lower) as root"); - set_euid(UID_OTHER); - - error = setrlimit(RLIMIT_DATA, &rl_raise_cur); - if (error == 0) - errx(-1, - "setrlimit(RLIMIT_DATA, raise_cur) succeeded as !root"); - if (errno != EPERM) - err(-1, "setrlimit(RLIMIT_DATA, raise_cur) wrong errno %d " - "as !root", errno); + if (initialized) + (void)setrlimit(RLIMIT_DATA, &rl_base); + initialized = 0; } diff --git a/tools/regression/priv/priv_sched_rtprio.c b/tools/regression/priv/priv_sched_rtprio.c index 72d1756..2498f3f 100644 --- a/tools/regression/priv/priv_sched_rtprio.c +++ b/tools/regression/priv/priv_sched_rtprio.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -54,181 +55,275 @@ #include "main.h" -static void -dummy(void) -{ - - while (1) - sleep(1); -} +static int childproc_running; +static pid_t childproc; -static void -collect(pid_t test_pid, pid_t dummy_pid) +int +priv_sched_rtprio_setup(int asroot, int injail, struct test *test) { - pid_t pid; + int another_uid, need_child; /* - * First, collect the main test process. When it has exited, then - * kill off the dummy process. + * Some tests require a second process with specific credentials. + * Set that up here, and kill in cleanup. */ - if (test_pid > 0) { - while (1) { - pid = waitpid(test_pid, NULL, 0); - if (pid == -1) - warn("waitpid(%d (test), NULL, 0)", test_pid); - if (pid == test_pid) - break; - } + need_child = 0; + if (test->t_test_func == priv_sched_rtprio_aproc_normal || + test->t_test_func == priv_sched_rtprio_aproc_idle || + test->t_test_func == priv_sched_rtprio_aproc_realtime) { + need_child = 1; + another_uid = 1; + } + if (test->t_test_func == priv_sched_rtprio_myproc_normal || + test->t_test_func == priv_sched_rtprio_myproc_idle || + test->t_test_func == priv_sched_rtprio_myproc_realtime) { + need_child = 1; } - if (kill(dummy_pid, SIGKILL) < 0) - err(-1, "kill(%d, SIGKILL)", dummy_pid); - - while (1) { - pid = waitpid(dummy_pid, NULL, 0); - if (pid == -1) - warn("waitpid(%d, NULL, 0)", dummy_pid); - if (pid == dummy_pid) - return; + if (need_child) { + childproc = fork(); + if (childproc < 0) { + warn("priv_sched_setup: fork"); + return (-1); + } + if (childproc == 0) { + if (another_uid) { + if (setresuid(UID_THIRD, UID_THIRD, + UID_THIRD) < 0) + err(-1, "setresuid(%d)", UID_THIRD); + } + while (1) + sleep(1); + } + childproc_running = 1; + sleep(1); /* Allow dummy thread to change uids. */ } + return (0); } -static void -test(pid_t dummy_pid) +void +priv_sched_rtprio_curproc_normal(int asroot, int injail, struct test *test) { struct rtprio rtp; int error; - /* - * Tests first as root. Test that we can set normal, realtime, and - * idle priorities on the current thread and on the dummy thread. - */ - rtp.type = RTP_PRIO_REALTIME; + rtp.type = RTP_PRIO_NORMAL; rtp.prio = 0; - if (rtprio(RTP_SET, 0, &rtp) < 0) - err(-1, "rtprio(RTP_SET, 0, {REALTIME, 0}) as root"); + error = rtprio(RTP_SET, 0, &rtp); + if (asroot && injail) + expect("priv_sched_rtprio_curproc_normal(asroot, injail)", + error, 0, 0); + if (asroot && !injail) + expect("priv_sched_rtprio_curproc_normal(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_sched_rtprio_curproc_normal(!asroot, injail)", + error, 0, 0); + if (!asroot && !injail) + expect("priv_sched_rtprio_curproc_normal(!asroot, !injail)", + error, 0, 0); +} + +void +priv_sched_rtprio_curproc_idle(int asroot, int injail, struct test *test) +{ + struct rtprio rtp; + int error; rtp.type = RTP_PRIO_IDLE; rtp.prio = 0; - if (rtprio(RTP_SET, 0, &rtp) < 0) - err(-1, "rtprio(RTP_SET, 0, {IDLE, 0}) as root"); + error = rtprio(RTP_SET, 0, &rtp); + if (asroot && injail) + expect("priv_sched_rtprio_curproc_idle(asroot, injail)", + error, -1, EPERM); + if (asroot && !injail) + expect("priv_sched_rtprio_curproc_idle(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_sched_rtprio_curproc_idle(!asroot, injail)", + error, -1, EPERM); + if (!asroot && !injail) + expect("priv_sched_rtprio_curproc_idle(!asroot, !injail)", + error, -1, EPERM); +} - rtp.type = RTP_PRIO_NORMAL; - rtp.prio = 0; - if (rtprio(RTP_SET, 0, &rtp) < 0) - err(-1, "rtprio(RTP_SET, 0, {NORMAL, 0) as root"); +void +priv_sched_rtprio_curproc_realtime(int asroot, int injail, struct test *test) +{ + struct rtprio rtp; + int error; rtp.type = RTP_PRIO_REALTIME; rtp.prio = 0; - if (rtprio(RTP_SET, dummy_pid, &rtp) < 0) - err(-1, "rtprio(RTP_SET, %d, {REALTIME, 0}) as root", - dummy_pid); + error = rtprio(RTP_SET, 0, &rtp); + if (asroot && injail) + expect("priv_sched_rtprio_curproc_realtime(asroot, injail)", + error, -1, EPERM); + if (asroot && !injail) + expect("priv_sched_rtprio_curproc_realtime(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_sched_rtprio_curproc_realtime(!asroot, injail)", + error, -1, EPERM); + if (!asroot && !injail) + expect("priv_sched_rtprio_curproc_realtime(!asroot, !injail)", + error, -1, EPERM); +} - rtp.type = RTP_PRIO_IDLE; - rtp.prio = 0; - if (rtprio(RTP_SET, dummy_pid, &rtp) < 0) - err(-1, "rtprio(RTP_SET, %d, {IDLE, 0}) as root", dummy_pid); +void +priv_sched_rtprio_myproc_normal(int asroot, int injail, struct test *test) +{ + struct rtprio rtp; + int error; rtp.type = RTP_PRIO_NORMAL; rtp.prio = 0; - if (rtprio(RTP_SET, dummy_pid, &rtp) < 0) - err(-1, "rtprio(RTP_SET, %d, {NORMAL, 0) as root", - dummy_pid); + error = rtprio(RTP_SET, 0, &rtp); + if (asroot && injail) + expect("priv_sched_rtprio_myproc_normal(asroot, injail)", + error, 0, 0); + if (asroot && !injail) + expect("priv_sched_rtprio_myproc_normal(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_sched_rtprio_myproc_normal(!asroot, injail)", + error, 0, 0); + if (!asroot && !injail) + expect("priv_sched_rtprio_myproc_normal(!asroot, !injail)", + error, 0, 0); +} - /* - * Then test again as a different credential. - */ - if (setresuid(UID_OTHER, UID_OTHER, UID_OTHER) < 0) - err(-1, "setresuid(%d)", UID_OTHER); +void +priv_sched_rtprio_myproc_idle(int asroot, int injail, struct test *test) +{ + struct rtprio rtp; + int error; - rtp.type = RTP_PRIO_REALTIME; + rtp.type = RTP_PRIO_IDLE; rtp.prio = 0; error = rtprio(RTP_SET, 0, &rtp); - if (error == 0) - errx(-1, - "rtprio(RTP_SET, 0, {REALTIME, 0}) succeeded as !root"); - if (errno != EPERM) - err(-1, "rtprio(RTP_SET, 0, {REALTIME, 0}) wrong errno %d as" - " !root", errno); + if (asroot && injail) + expect("priv_sched_rtprio_myproc_idle(asroot, injail)", + error, -1, EPERM); + if (asroot && !injail) + expect("priv_sched_rtprio_myproc_idle(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_sched_rtprio_myproc_idle(!asroot, injail)", + error, -1, EPERM); + if (!asroot && !injail) + expect("priv_sched_rtprio_myproc_idle(!asroot, !injail)", + error, -1, EPERM); +} - rtp.type = RTP_PRIO_IDLE; +void +priv_sched_rtprio_myproc_realtime(int asroot, int injail, struct test *test) +{ + struct rtprio rtp; + int error; + + rtp.type = RTP_PRIO_REALTIME; rtp.prio = 0; error = rtprio(RTP_SET, 0, &rtp); - if (error == 0) - errx(-1, "rtprio(RTP_SET, 0, {IDLE, 0}) succeeded as !root"); - if (errno != EPERM) - err(-1, "rtprio(RTP_SET, 0, {IDLE, 0}) wrong errno %d as " - "!root", errno); + if (asroot && injail) + expect("priv_sched_rtprio_myproc_realtime(asroot, injail)", + error, -1, EPERM); + if (asroot && !injail) + expect("priv_sched_rtprio_myproc_realtime(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_sched_rtprio_myproc_realtime(!asroot, injail)", + error, -1, EPERM); + if (!asroot && !injail) + expect("priv_sched_rtprio_myproc_realtime(!asroot, !injail)", + error, -1, EPERM); +} + +void +priv_sched_rtprio_aproc_normal(int asroot, int injail, struct test *test) +{ + struct rtprio rtp; + int error; rtp.type = RTP_PRIO_NORMAL; rtp.prio = 0; - if (rtprio(RTP_SET, 0, &rtp) < 0) - err(-1, "rtprio(RTP_SET, 0, {NORMAL, 0}) as !root"); + error = rtprio(RTP_SET, childproc, &rtp); + if (asroot && injail) + expect("priv_sched_rtprio_aproc_normal(asroot, injail)", + error, -1, ESRCH); + if (asroot && !injail) + expect("priv_sched_rtprio_aproc_normal(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_sched_rtprio_aproc_normal(!asroot, injail)", + error, -1, ESRCH); + if (!asroot && !injail) + expect("priv_sched_rtprio_aproc_normal(!asroot, !injail)", + error, -1, EPERM); +} - rtp.type = RTP_PRIO_REALTIME; - rtp.prio = 0; - error = rtprio(RTP_SET, dummy_pid, &rtp); - if (error == 0) - errx(-1, - "rtprio(RTP_SET, %d, {REALTIME, 0}) succeeded as !root", - dummy_pid); - if (errno != EPERM) - err(-1, "rtprio(RTP_SET, %d, {REALTIME, 0}) wrong errno %d as" - " !root", dummy_pid, errno); +void +priv_sched_rtprio_aproc_idle(int asroot, int injail, struct test *test) +{ + struct rtprio rtp; + int error; rtp.type = RTP_PRIO_IDLE; rtp.prio = 0; - error = rtprio(RTP_SET, dummy_pid, &rtp); - if (error == 0) - errx(-1, "rtprio(RTP_SET, %d, {IDLE, 0}) succeeded as !root", - dummy_pid); - if (errno != EPERM) - err(-1, - "rtprio(RTP_SET, %d, {IDLE, 0}) wrong errno %d as !root", - dummy_pid, errno); - - rtp.type = RTP_PRIO_NORMAL; - rtp.prio = 0; - error = rtprio(RTP_SET, dummy_pid, &rtp); - if (error == 0) - errx(-1, - "rtprio(RTP_SET, %d, {NORMAL, 0) succeeded as !root", - dummy_pid); - if (errno != EPERM) - err(-1, "rtprio(RTP_SET, %d, {NORMAL, 0}) wrong errno %d as " - "!root", dummy_pid, errno); - - exit(0); + error = rtprio(RTP_SET, childproc, &rtp); + if (asroot && injail) + expect("priv_sched_rtprio_aproc_idle(asroot, injail)", + error, -1, ESRCH); + if (asroot && !injail) + expect("priv_sched_rtprio_aproc_idle(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_sched_rtprio_aproc_idle(!asroot, injail)", + error, -1, ESRCH); + if (!asroot && !injail) + expect("priv_sched_rtprio_aroc_idle(!asroot, !injail)", + error, -1, EPERM); } void -priv_sched_rtprio(void) +priv_sched_rtprio_aproc_realtime(int asroot, int injail, struct test *test) { - pid_t dummy_pid, test_pid; + struct rtprio rtp; + int error; - assert_root(); + rtp.type = RTP_PRIO_REALTIME; + rtp.prio = 0; + error = rtprio(RTP_SET, childproc, &rtp); + if (asroot && injail) + expect("priv_sched_rtprio_aproc_realtime(asroot, injail)", + error, -1, ESRCH); + if (asroot && !injail) + expect("priv_sched_rtprio_aproc_realtime(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_sched_rtprio_aproc_realtime(!asroot, injail)", + error, -1, ESRCH); + if (!asroot && !injail) + expect("priv_sched_rtprio_aproc_realtime(!asroot, !injail)", + error, -1, EPERM); +} - /* - * Set up dummy process, which we will kill before exiting. - */ - dummy_pid = fork(); - if (dummy_pid < 0) - err(-1, "fork - dummy"); - if (dummy_pid == 0) { - if (setresuid(UID_THIRD, UID_THIRD, UID_THIRD) < 0) - err(-1, "setresuid(%d)", UID_THIRD); - dummy(); - } - sleep(1); /* Allow dummy thread to change uids. */ +void +priv_sched_rtprio_cleanup(int asroot, int injail, struct test *test) +{ + pid_t pid; - test_pid = fork(); - if (test_pid < 0) { - warn("fork - test"); - collect(-1, dummy_pid); - return; + if (childproc_running) { + (void)kill(childproc, SIGKILL); + while (1) { + pid = waitpid(childproc, NULL, 0); + if (pid == -1) + warn("waitpid(%d (test), NULL, 0)", + childproc); + if (pid == childproc) + break; + } + childproc_running = 0; + childproc = -1; } - if (test_pid == 0) - test(dummy_pid); - - collect(test_pid, dummy_pid); } diff --git a/tools/regression/priv/priv_sched_setpriority.c b/tools/regression/priv/priv_sched_setpriority.c index 4d56813..219fd8c 100644 --- a/tools/regression/priv/priv_sched_setpriority.c +++ b/tools/regression/priv/priv_sched_setpriority.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -50,114 +51,123 @@ #include "main.h" -static void -dummy(void) -{ - - while (1) - sleep(1); -} +static int childproc_running; +static pid_t childproc; -static void -collect(pid_t test_pid, pid_t dummy_pid) +int +priv_sched_setpriority_setup(int asroot, int injail, struct test *test) { - pid_t pid; + int another_uid, need_child; /* - * First, collect the main test process. When it has exited, then - * kill off the dummy process. + * Some tests require a second process with specific credentials. + * Set that up here, and kill in cleanup. */ - if (test_pid > 0) { - while (1) { - pid = waitpid(test_pid, NULL, 0); - if (pid == -1) - warn("waitpid(%d (test), NULL, 0)", test_pid); - if (pid == test_pid) - break; - } + need_child = 0; + if (test->t_test_func == priv_sched_setpriority_aproc) { + need_child = 1; + another_uid = 1; } - - if (kill(dummy_pid, SIGKILL) < 0) - err(-1, "kill(%d, SIGKILL)", dummy_pid); - - while (1) { - pid = waitpid(dummy_pid, NULL, 0); - if (pid == -1) - warn("waitpid(%d, NULL, 0)", dummy_pid); - if (pid == dummy_pid) - return; + if (test->t_test_func == priv_sched_setpriority_myproc) + need_child = 1; + + if (need_child) { + childproc = fork(); + if (childproc < 0) { + warn("priv_sched_setup: fork"); + return (-1); + } + if (childproc == 0) { + if (another_uid) { + if (setresuid(UID_THIRD, UID_THIRD, + UID_THIRD) < 0) + err(-1, "setresuid(%d)", UID_THIRD); + } + while (1) + sleep(1); + } + childproc_running = 1; + sleep(1); /* Allow dummy thread to change uids. */ } + return (0); } -static void -test(pid_t dummy_pid) +void +priv_sched_setpriority_curproc(int asroot, int injail, struct test *test) { int error; - /* - * Tests first as root. - */ - if (setpriority(PRIO_PROCESS, 0, -1) < 0) - err(-1, "setpriority(PRIO_PROCESS, 0, -1) as root"); + error = setpriority(PRIO_PROCESS, 0, -1); + if (asroot && injail) + expect("priv_sched_setpriority_curproc(asroot, injail)", + error, -1, EACCES); + if (asroot && !injail) + expect("priv_sched_setpriority_curproc(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_sched_setpriority_curproc(!asroot, injail)", + error, -1, EACCES); + if (!asroot && !injail) + expect("priv_sched_setpriority_curproc(!asroot, !injail)", + error, -1, EACCES); +} - if (setpriority(PRIO_PROCESS, dummy_pid, -1) < 0) - err(-1, "setpriority(PRIO_PROCESS, %d, -1) as root", - dummy_pid); +void +priv_sched_setpriority_myproc(int asroot, int injail, struct test *test) +{ + int error; - /* - * Then test again as a different credential. - */ - if (setresuid(UID_OTHER, UID_OTHER, UID_OTHER) < 0) - err(-1, "setresuid(%d)", UID_OTHER); - - error = setpriority(PRIO_PROCESS, 0, -2); - if (error == 0) - errx(-1, - "setpriority(PRIO_PROCESS, 0, -2) succeeded as !root"); - if (errno != EACCES) - err(-1, "setpriority(PRIO_PROCESS, 0, 2) wrong errno %d as " - "!root", errno); - - error = setpriority(PRIO_PROCESS, dummy_pid, -2); - if (error == 0) - errx(-1, - "setpriority(PRIO_PROCESS, %d, -2) succeeded as !root", - dummy_pid); - if (errno != EPERM) - err(-1, "setpriority(PRIO_PROCESS, %d, 2) wrong errno %d as " - "!root", dummy_pid, errno); - - exit(0); + error = setpriority(PRIO_PROCESS, 0, -1); + if (asroot && injail) + expect("priv_sched_setpriority_myproc(asroot, injail)", + error, -1, EACCES); + if (asroot && !injail) + expect("priv_sched_setpriority_myproc(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_sched_setpriority_myproc(!asroot, injail)", + error, -1, EACCES); + if (!asroot && !injail) + expect("priv_sched_setpriority_myproc(!asroot, !injail)", + error, -1, EACCES); } void -priv_sched_setpriority(void) +priv_sched_setpriority_aproc(int asroot, int injail, struct test *test) { - pid_t dummy_pid, test_pid; + int error; - assert_root(); + error = setpriority(PRIO_PROCESS, 0, -1); + if (asroot && injail) + expect("priv_sched_setpriority_aproc(asroot, injail)", + error, -1, EACCES); + if (asroot && !injail) + expect("priv_sched_setpriority_aproc(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_sched_setpriority_aproc(!asroot, injail)", + error, -1, EACCES); + if (!asroot && !injail) + expect("priv_sched_setpriority_aproc(!asroot, !injail)", + error, -1, EACCES); +} - /* - * Set up dummy process, which we will kill before exiting. - */ - dummy_pid = fork(); - if (dummy_pid < 0) - err(-1, "fork - dummy"); - if (dummy_pid == 0) { - if (setresuid(UID_THIRD, UID_THIRD, UID_THIRD) < 0) - err(-1, "setresuid(%d)", UID_THIRD); - dummy(); - } - sleep(1); /* Allow dummy thread to change uids. */ +void +priv_sched_setpriority_cleanup(int asroot, int injail, struct test *test) +{ + pid_t pid; - test_pid = fork(); - if (test_pid < 0) { - warn("fork - test"); - collect(-1, dummy_pid); - return; + if (childproc_running) { + (void)kill(childproc, SIGKILL); + while (1) { + pid = waitpid(childproc, NULL, 0); + if (pid == -1) + warn("waitpid(%d (test), NULL, 0)", + childproc); + if (pid == childproc) + break; + } + childproc_running = 0; + childproc = -1; } - if (test_pid == 0) - test(dummy_pid); - - collect(test_pid, dummy_pid); } diff --git a/tools/regression/priv/priv_settimeofday.c b/tools/regression/priv/priv_settimeofday.c index d18582f..df9300e 100644 --- a/tools/regression/priv/priv_settimeofday.c +++ b/tools/regression/priv/priv_settimeofday.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -43,34 +44,40 @@ #include "main.h" -void -priv_settimeofday(void) +static struct timeval now; + +int +priv_settimeofday_setup(int asroot, int injail, struct test *test) { - struct timeval tv; - int error; - assert_root(); + if (gettimeofday(&now, NULL) < 0) { + warn("priv_settimeofday_setup: gettimeofday"); + return (-1); + } + return (0); +} - /* - * Query time. - */ - if (gettimeofday(&tv, NULL) < 0) - err(-1, "gettimeofday"); +void +priv_settimeofday(int asroot, int injail, struct test *test) +{ + int error; - /* - * Set with privilege. - */ - if (settimeofday(&tv, NULL) < 0) - err(-1, "settimeofday as root"); + error = settimeofday(&now, NULL); + if (asroot && injail) + expect("priv_settimeofday(asroot, injail)", error, -1, + EPERM); + if (asroot && !injail) + expect("priv_settimeofday(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_settimeofday(!asroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_settimeofday(!asroot, !injail)", error, -1, + EPERM); +} - /* - * Set without privilege. - */ - set_euid(UID_OTHER); +void +priv_settimeofday_cleanup(int asroot, int injail, struct test *test) +{ - error = settimeofday(&tv, NULL); - if (error == 0) - errx(-1, "settimeofday succeeded as !root"); - if (errno != EPERM) - errx(-1, "settimeofday wrong errno %d as !root", errno); } diff --git a/tools/regression/priv/priv_sysctl_write.c b/tools/regression/priv/priv_sysctl_write.c index becff06..25e02f9 100644 --- a/tools/regression/priv/priv_sysctl_write.c +++ b/tools/regression/priv/priv_sysctl_write.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,9 +31,12 @@ */ /* - * Test that sysctls can only be written with privilege by trying first with, - * then without privilege. Do this by first reading, then setting the - * hostname as a no-op. + * Two privileges exist for writing sysctls -- one for sysctls writable only + * outside of jail (PRIV_SYSCTL_WRITE) and one for those also writable inside + * jail (PRIV_SYSCTL_WRITEJAIL). + * + * Test the prior by attempting to write to kern.domainname, and the latter + * by attempting to write to kern.hostname. */ #include @@ -46,44 +50,79 @@ #include "main.h" #define KERN_HOSTNAME_STRING "kern.hostname" +#define KERN_DOMAINNAME_STRING "kern.domainname" -void -priv_sysctl_write(void) +static char stored_hostname[1024]; +static char stored_domainname[1024]; + +int +priv_sysctl_write_setup(int asroot, int injail, struct test *test) { - char buffer[1024]; size_t len; int error; - assert_root(); - - /* - * First query the current value. - */ - len = sizeof(buffer); - error = sysctlbyname(KERN_HOSTNAME_STRING, buffer, &len, NULL, 0); - if (error) - err(-1, "sysctlbyname(\"%s\") query", KERN_HOSTNAME_STRING); - - /* - * Now try to set with privilege. - */ - error = sysctlbyname(KERN_HOSTNAME_STRING, NULL, NULL, buffer, - strlen(buffer)); - if (error) - err(-1, "sysctlbyname(\"%s\") set as root", + len = sizeof(stored_hostname); + error = sysctlbyname(KERN_HOSTNAME_STRING, stored_hostname, &len, + NULL, 0); + if (error) { + warn("priv_sysctl_write_setup: sysctlbyname(\"%s\")", KERN_HOSTNAME_STRING); + return (-1); + } - /* - * Now without privilege. - */ - set_euid(UID_OTHER); + len = sizeof(stored_hostname); + error = sysctlbyname(KERN_DOMAINNAME_STRING, stored_domainname, &len, + NULL, 0); + if (error) { + warn("priv_sysctl_write_setup: sysctlbyname(\"%s\")", + KERN_DOMAINNAME_STRING); + return (-1); + } + + return (0); +} + +void +priv_sysctl_write(int asroot, int injail, struct test *test) +{ + int error; + + error = sysctlbyname(KERN_DOMAINNAME_STRING, NULL, NULL, + stored_domainname, strlen(stored_domainname)); + if (asroot && injail) + expect("priv_sysctl_write(asroot, injail)", error, -1, + EPERM); + if (asroot && !injail) + expect("priv_sysctl_write(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_sysctl_write(!asroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_sysctl_write(!asroot, !injail)", error, -1, + EPERM); +} + +void +priv_sysctl_writejail(int asroot, int injail, struct test *test) +{ + int error; + + error = sysctlbyname(KERN_HOSTNAME_STRING, NULL, NULL, + stored_hostname, strlen(stored_hostname)); + if (asroot && injail) + expect("priv_sysctl_writejail(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_sysctl_writejail(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_sysctl_writejail(!asroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_sysctl_writejail(!asroot, !injail)", error, -1, + EPERM); +} + +void +priv_sysctl_write_cleanup(int asroot, int injail, struct test *test) +{ - error = sysctlbyname(KERN_HOSTNAME_STRING, NULL, NULL, buffer, - strlen(buffer)); - if (error == 0) - errx(-1, "sysctlbyname(\"%s\") succeeded as !root", - KERN_HOSTNAME_STRING); - if (errno != EPERM) - err(-1, "sysctlbyname(\"%s\") wrong errno %d", - KERN_HOSTNAME_STRING, errno); } diff --git a/tools/regression/priv/priv_vfs_admin.c b/tools/regression/priv/priv_vfs_admin.c deleted file mode 100644 index f06e9b2..0000000 --- a/tools/regression/priv/priv_vfs_admin.c +++ /dev/null @@ -1,328 +0,0 @@ -/*- - * Copyright (c) 2006 nCircle Network Security, Inc. - * All rights reserved. - * - * This software was developed by Robert N. M. Watson for the TrustedBSD - * Project under contract to nCircle Network Security, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, - * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * Check that privilege is required for a variety of administrative - * activities on a file owned by another user. Admin privileges are required - * for the following services: - * - * - Set file flags. - * - Set utimes to non-NULL. - * - Set file mode. - * - Set file ownership. - * - Remove a file from a sticky directory. (XXXRW: Not tested here.) - * - Set the ACL on a file. (XXXRW: Not tested here.) - * - Delete the ACL on a file. (XXXRW: Not tested here.) - */ - -#include -#include - -#include -#include -#include -#include -#include - -#include "main.h" - -static u_long -getflags(char *fpathp) -{ - struct stat sb; - - if (stat(fpathp, &sb) < 0) - err(-1, "stat(%s)", fpathp); - - return (sb.st_flags); -} - -static void -priv_vfs_admin_chflags(void) -{ - char fpath[1024]; - u_long flags; - int error; - - /* - * Test that setting file flags works as and not as the file owner - * when running with privilege, but only as the file owner when - * running without privilege. - */ - setup_file(fpath, UID_ROOT, GID_WHEEL, 0600); - flags = getflags(fpath); - flags |= UF_NODUMP; - if (chflags(fpath, flags) < 0) { - warn("chflags(%s, UF_NODUMP) owner as root", fpath); - goto out; - } - (void)unlink(fpath); - - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - flags = getflags(fpath); - flags |= UF_NODUMP; - if (chflags(fpath, flags) < 0) { - warn("chflags(%s, UF_NODUMP) !owner as root", fpath); - goto out; - } - (void)unlink(fpath); - - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - flags = getflags(fpath); - flags |= UF_NODUMP; - set_euid(UID_OWNER); - if (chflags(fpath, flags) < 0) { - warn("chflags(%s, UF_NODUMP) owner as !root", fpath); - goto out; - } - set_euid(UID_ROOT); - (void)unlink(fpath); - - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - flags = getflags(fpath); - flags |= UF_NODUMP; - set_euid(UID_OTHER); - error = chflags(fpath, flags); - if (error == 0) { - warnx("chflags(%s, UF_NODUMP) succeeded !owner as !root", - fpath); - goto out; - } - if (errno != EPERM) { - warn("chflags(%s, UF_NODUMP) wrong errno %d !owner a !root", - fpath, errno); - goto out; - } - set_euid(UID_ROOT); - (void)unlink(fpath); - -out: - (void)seteuid(UID_ROOT); - (void)unlink(fpath); -} - -static void -priv_vfs_admin_utimes(void) -{ - struct timeval tv[2]; - char fpath[1024]; - int error; - - /* - * Actual values don't matter here. - */ - tv[0].tv_sec = 0; - tv[0].tv_usec = 0; - tv[1].tv_sec = 0; - tv[1].tv_usec = 0; - - /* - * When using a non-NULL argument to utimes(), must either hold - * privilege or be the file owner. Check all four possible - * combinations of privilege, ownership. - */ - setup_file(fpath, UID_ROOT, GID_WHEEL, 0600); - if (utimes(fpath, tv) < 0) { - warn("utimes(%s, !NULL) owner as root", fpath); - goto out; - } - (void)unlink(fpath); - - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - if (utimes(fpath, tv) < 0) { - warn("utimes(%s, !NULL) !owner as root", fpath); - goto out; - } - (void)unlink(fpath); - - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - set_euid(UID_OWNER); - if (utimes(fpath, tv) < 0) { - warn("utimes(%s, !NULL) owner as !root", fpath); - goto out; - } - set_euid(UID_ROOT); - (void)unlink(fpath); - - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - set_euid(UID_OTHER); - error = utimes(fpath, tv); - if (error == 0) { - warnx("utimes(%s, !NULL) succeeded !owner as !root", - fpath); - goto out; - } - if (errno != EPERM) { - warn("utimes(%s, !NULL) wrong errno %d !owner a !root", - fpath, errno); - goto out; - } - set_euid(UID_ROOT); - (void)unlink(fpath); - -out: - (void)seteuid(UID_ROOT); - (void)unlink(fpath); -} - -static void -priv_vfs_admin_chmod(void) -{ - char fpath[1024]; - int error; - - /* - * Test that setting file permissions works either as file owner or - * not when running with privilege, but only as file owner when - * running without privilege. - */ - setup_file(fpath, UID_ROOT, GID_WHEEL, 0600); - if (chmod(fpath, 0640) < 0) { - warn("chmod(%s, 0640) owner as root", fpath); - goto out; - } - (void)unlink(fpath); - - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - if (chmod(fpath, 0640) < 0) { - warn("chmod(%s, 0640) !owner as root", fpath); - goto out; - } - (void)unlink(fpath); - - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - set_euid(UID_OWNER); - if (chmod(fpath, 0640) < 0) { - warn("chmod(%s, 0640) owner as !root", fpath); - goto out; - } - set_euid(UID_ROOT); - (void)unlink(fpath); - - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - set_euid(UID_OTHER); - error = chmod(fpath, 0640); - if (error == 0) { - warnx("chmod(%s, 0640) succeeded !owner as !root", - fpath); - goto out; - } - if (errno != EPERM) { - warn("chmod(%s, 0640) wrong errno %d !owner a !root", - fpath, errno); - goto out; - } - set_euid(UID_ROOT); - (void)unlink(fpath); - -out: - (void)seteuid(UID_ROOT); - (void)unlink(fpath); -} - -static const gid_t gidset[] = { GID_WHEEL, GID_OWNER, GID_OTHER}; - -static void -priv_vfs_admin_chown(void) -{ - char fpath[1024]; - int error; - - /* - * Test that the group of the file can only be changed with privilege - * or as the owner. These test is run last as it frobs the group - * context. We change the file group from one group we're in to - * another we're in to avoid any other access control checks failing. - */ - if (setgroups(3, gidset) < 0) - err(-1, "priv_vfs_admin_chown:setgroups(3, {%d, %d, %d})", - GID_WHEEL, GID_OWNER, GID_OTHER); - - /* - * Test that setting file permissions works either as file owner or - * not when running with privilege, but only as file owner when - * running without privilege. - */ - setup_file(fpath, UID_ROOT, GID_WHEEL, 0600); - if (chown(fpath, -1, GID_OWNER) < 0) { - warn("chown(%s, %d) owner as root", fpath, GID_OWNER); - goto out; - } - (void)unlink(fpath); - - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - if (chown(fpath, -1, GID_OWNER) < 0) { - warn("chown(%s, %d) !owner as root", fpath, GID_OWNER); - goto out; - } - (void)unlink(fpath); - - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - set_euid(UID_OWNER); - if (chown(fpath, -1, GID_OWNER) < 0) { - warn("chown(%s, %d) owner as !root", fpath, GID_OWNER); - goto out; - } - set_euid(UID_ROOT); - (void)unlink(fpath); - - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - set_euid(UID_OTHER); - error = chown(fpath, -1, GID_OWNER); - if (error == 0) { - warnx("chown(%s, %d) succeeded !owner as !root", - fpath, GID_OWNER); - goto out; - } - if (errno != EPERM) { - warn("chown(%s, %d) wrong errno %d !owner a !root", - fpath, GID_OWNER, errno); - goto out; - } - set_euid(UID_ROOT); - (void)unlink(fpath); - -out: - (void)seteuid(UID_ROOT); - (void)unlink(fpath); -} - -void -priv_vfs_admin(void) -{ - - assert_root(); - - priv_vfs_admin_chflags(); - priv_vfs_admin_utimes(); - priv_vfs_admin_chmod(); - priv_vfs_admin_chown(); /* Run this last. */ -} diff --git a/tools/regression/priv/priv_vfs_chflags.c b/tools/regression/priv/priv_vfs_chflags.c new file mode 100644 index 0000000..469b12b --- /dev/null +++ b/tools/regression/priv/priv_vfs_chflags.c @@ -0,0 +1,254 @@ +/*- + * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson + * All rights reserved. + * + * This software was developed by Robert N. M. Watson for the TrustedBSD + * Project under contract to nCircle Network Security, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, + * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Test privileges associated with setting file flags on files; whether or + * not it requires privilege depends on the flag, and some flags cannot be + * set in jail at all. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "main.h" + +static char fpath[1024]; +static int fpath_initialized; + +/* + * For chflags, we consider three dimmensions: process owner, file owner, and + * flag type. The calling framework handles variations in process owner; the + * rest are handled via multiple tests. One cleanup function is used. + */ +static u_long +getflags(char *fpathp) +{ + struct stat sb; + + if (stat(fpathp, &sb) < 0) + err(-1, "stat(%s)", fpathp); + + return (sb.st_flags); +} + +int +priv_vfs_chflags_froot_setup(int asroot, int injail, struct test *test) +{ + + setup_file("priv_vfs_chflags_froot_setup: fpath", fpath, UID_ROOT, + GID_WHEEL, 0600); + fpath_initialized = 1; + return (0); +} + +int +priv_vfs_chflags_fowner_setup(int asroot, int injail, + struct test *test) +{ + + setup_file("priv_vfs_chflags_fowner_setup: fpath", fpath, UID_OWNER, + GID_OWNER, 0600); + fpath_initialized = 1; + return (0); +} + +int +priv_vfs_chflags_fother_setup(int asroot, int injail, + struct test *test) +{ + + setup_file("priv_vfs_chflags_fowner_setup: fpath", fpath, UID_OTHER, + GID_OTHER, 0600); + fpath_initialized = 1; + return (0); +} + +void +priv_vfs_chflags_froot_uflags(int asroot, int injail, + struct test *test) +{ + u_long flags; + int error; + + flags = getflags(fpath); + flags |= UF_NODUMP; + error = chflags(fpath, flags); + if (asroot && injail) + expect("priv_vfs_chflags_froot_uflags(asroot, injail)", + error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_chflags_froot_uflags(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_chflags_froot_uflags(!asroot, injail)", + error, -1, EPERM); + if (!asroot && !injail) + expect("priv_vfs_chflags_froot_uflags(!asroot, !injail)", + error, -1, EPERM); +} + +void +priv_vfs_chflags_fowner_uflags(int asroot, int injail, + struct test *test) +{ + u_long flags; + int error; + + flags = getflags(fpath); + flags |= UF_NODUMP; + error = chflags(fpath, flags); + if (asroot && injail) + expect("priv_vfs_chflags_fowner_uflags(asroot, injail)", + error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_chflags_fowner_uflags(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_chflags_fowner_uflags(!asroot, injail)", + error, 0, 0); + if (!asroot && !injail) + expect("priv_vfs_chflags_fowner_uflags(!asroot, !injail)", + error, 0, 0); +} + +void +priv_vfs_chflags_fother_uflags(int asroot, int injail, + struct test *test) +{ + u_long flags; + int error; + + flags = getflags(fpath); + flags |= UF_NODUMP; + error = chflags(fpath, flags); + if (asroot && injail) + expect("priv_vfs_chflags_fother_uflags(asroot, injail)", + error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_chflags_fother_uflags(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_chflags_fother_uflags(!asroot, injail)", + error, -1, EPERM); + if (!asroot && !injail) + expect("priv_vfs_chflags_fother_uflags(!asroot, !injail)", + error, -1, EPERM); +} + +void +priv_vfs_chflags_froot_sflags(int asroot, int injail, + struct test *test) +{ + u_long flags; + int error; + + flags = getflags(fpath); + flags |= SF_ARCHIVED; + error = chflags(fpath, flags); + if (asroot && injail) + expect("priv_vfs_chflags_froot_sflags(asroot, injail)", + error, -1, EPERM); + if (asroot && !injail) + expect("priv_vfs_chflags_froot_sflags(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_chflags_froot_sflags(!asroot, injail)", + error, -1, EPERM); + if (!asroot && !injail) + expect("priv_vfs_chflags_froot_sflags(!asroot, !injail)", + error, -1, EPERM); +} + +void +priv_vfs_chflags_fowner_sflags(int asroot, int injail, + struct test *test) +{ + u_long flags; + int error; + + flags = getflags(fpath); + flags |= SF_ARCHIVED; + error = chflags(fpath, flags); + if (asroot && injail) + expect("priv_vfs_chflags_fowner_sflags(asroot, injail)", + error, -1, EPERM); + if (asroot && !injail) + expect("priv_vfs_chflags_fowner_sflags(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_chflags_fowner_sflags(!asroot, injail)", + error, -1, EPERM); + if (!asroot && !injail) + expect("priv_vfs_chflags_fowner_sflags(!asroot, !injail)", + error, -1, EPERM); +} + +void +priv_vfs_chflags_fother_sflags(int asroot, int injail, + struct test *test) +{ + u_long flags; + int error; + + flags = getflags(fpath); + flags |= SF_ARCHIVED; + error = chflags(fpath, flags); + if (asroot && injail) + expect("priv_vfs_chflags_fother_sflags(asroot, injail)", + error, -1, EPERM); + if (asroot && !injail) + expect("priv_vfs_chflags_fother_sflags(asroot, !injail)", + error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_chflags_fother_sflags(!asroot, injail)", + error, -1, EPERM); + if (!asroot && !injail) + expect("priv_vfs_chflags_fother_sflags(!asroot, !injail)", + error, -1, EPERM); +} + +void +priv_vfs_chflags_cleanup(int asroot, int injail, struct test *test) +{ + + if (fpath_initialized) { + (void)chflags(fpath, 0); + (void)unlink(fpath); + fpath_initialized = 0; + } +} diff --git a/tools/regression/priv/priv_vfs_chmod.c b/tools/regression/priv/priv_vfs_chmod.c new file mode 100644 index 0000000..6a64871 --- /dev/null +++ b/tools/regression/priv/priv_vfs_chmod.c @@ -0,0 +1,146 @@ +/*- + * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson + * All rights reserved. + * + * This software was developed by Robert N. M. Watson for the TrustedBSD + * Project under contract to nCircle Network Security, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, + * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Check that we must either be running as root or the owner of the file in + * order to modify permissions on the file. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "main.h" + +static char fpath[1024]; +static int fpath_initialized; + +int +priv_vfs_chmod_froot_setup(int asroot, int injail, struct test *test) +{ + + setup_file("priv_vfs_chmod_setup: fpath", fpath, UID_ROOT, GID_WHEEL, + 0600); + fpath_initialized = 1; + return (0); +} + +int +priv_vfs_chmod_fowner_setup(int asroot, int injail, struct test *test) +{ + + setup_file("priv_vfs_chmod_setup: fpath", fpath, UID_OWNER, + GID_OWNER, 0600); + fpath_initialized = 1; + return (0); +} + +int +priv_vfs_chmod_fother_setup(int asroot, int injail, struct test *test) +{ + + setup_file("priv_vfs_chmod_setup: fpath", fpath, UID_OTHER, + GID_OTHER, 0600); + fpath_initialized = 1; + return (0); +} + +void +priv_vfs_chmod_froot(int asroot, int injail, struct test *test) +{ + int error; + + error = chmod(fpath, 0640); + if (asroot && injail) + expect("priv_vfs_chmod_froot(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_chmod_froot(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_chmod_froot(!asroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_vfs_chmod_froot(!asroot, !injail)", error, -1, + EPERM); +} + +void +priv_vfs_chmod_fowner(int asroot, int injail, struct test *test) +{ + int error; + + error = chmod(fpath, 0640); + if (asroot && injail) + expect("priv_vfs_chmod_fowner(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_chmod_fowner(asroot, !injail)", error, 0, + 0); + if (!asroot && injail) + expect("priv_vfs_chmod_fowner(!asroot, injail)", error, 0, + 0); + if (!asroot && !injail) + expect("priv_vfs_chmod_fowner(!asroot, !injail)", error, 0, + 0); +} + +void +priv_vfs_chmod_fother(int asroot, int injail, struct test *test) +{ + int error; + + error = chmod(fpath, 0640); + if (asroot && injail) + expect("priv_vfs_chmod_fother(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_chmod_fother(asroot, !injail)", error, 0, + 0); + if (!asroot && injail) + expect("priv_vfs_chmod_fother(!asroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_vfs_chmod_fother(!asroot, !injail)", error, -1, + EPERM); +} + +void +priv_vfs_chmod_cleanup(int asroot, int injail, struct test *test) +{ + + if (fpath_initialized) { + (void)unlink(fpath); + fpath_initialized = 0; + } +} diff --git a/tools/regression/priv/priv_vfs_chown.c b/tools/regression/priv/priv_vfs_chown.c index 8d72ac2..c0c10e6 100644 --- a/tools/regression/priv/priv_vfs_chown.c +++ b/tools/regression/priv/priv_vfs_chown.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert M. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -50,121 +51,114 @@ #include "main.h" -const gid_t gidset[] = {GID_WHEEL, GID_OWNER}; +static char fpath[1024]; +static int fpath_initialized; + +/* + * Check that changing the uid of a file requires privilege. + */ +int +priv_vfs_chown_uid_setup(int asroot, int injail, struct test *test) +{ + + setup_file("priv_vfs_chown_uid: fpath", fpath, UID_ROOT, GID_WHEEL, + 0600); + fpath_initialized = 1; + return (0); +} void -priv_vfs_chown(void) +priv_vfs_chown_uid(int asroot, int injail, struct test *test) { - char fpath[1024]; int error; - assert_root(); + error = chown(fpath, UID_OWNER, -1); + if (asroot && injail) + expect("priv_vfs_chown_uid(root, jail)", error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_chown_uid(root, !jail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_chown_uid(!root, jail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_vfs_chown_uid(!root, !jail)", error, -1, EPERM); +} - /* - * Before beginning, set up group set for process. Place in wheel - * and owner groups; don't put in other group so that when we chown - * to the other group, it's as a non-member. - */ - if (setgroups(2, gidset) < 0) - err(-1, "setgroups(2, {%d, %d})", GID_WHEEL, GID_OWNER); +/* + * Check that changing the gid of a file owned by the user is allowed without + * privilege as long as the gid matches the process. + */ +int +priv_vfs_chown_mygid_setup(int asroot, int injail, struct test *test) +{ /* - * In the first pass, confirm that all works as desired with - * privilege. - * - * Check that chown when non-owner works fine. Do a no-op change to - * avoid other permission checks. Note that we can't request - * (-1, -1) and get an access control check, we have to request - * specific uid/gid that are not the same. + * Create a file with a matching uid to the test process, but not a + * matching gid. */ - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - if (chown(fpath, -1, GID_OWNER) < 0) { - warn("chown(%s, -1, %d) as root", fpath, GID_OWNER); - goto out; - } - (void)unlink(fpath); + setup_file("priv_vfs_chown_mygid: fpath", fpath, asroot ? UID_ROOT : + UID_OWNER, GID_OTHER, 0600); + fpath_initialized = 1; + return (0); +} - /* - * Check that chown changing uid works with privilege. - */ - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - if (chown(fpath, UID_OTHER, -1) < 0) { - warn("chown(%s, %d, -1) as root", fpath, UID_OTHER); - goto out; - } - (void)unlink(fpath); +void +priv_vfs_chown_mygid(int asroot, int injail, struct test *test) +{ + int error; - /* - * Check that can change the file group to one we are not a member of - * when running with privilege. - */ - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - if (chown(fpath, -1, GID_OTHER) < 0) { - warn("chown(%s, -1, %d) as root", fpath, GID_OTHER); - goto out; - } - (void)unlink(fpath); + error = chown(fpath, -1, asroot ? GID_WHEEL : GID_OWNER); + if (asroot && injail) + expect("priv_vfs_chown_mygid(root, jail)", error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_chown_mygid(root, !jail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_chown_mygid(!root, !jail)", error, 0, 0); + if (!asroot && !injail) + expect("priv_vfs_chown_mygid(!root, !jail)", error, 0, 0); +} - /* - * Now, the same again, but without privilege. - * - * Confirm that we can't chown a file we don't own, even as a no-op. - */ - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - set_euid(UID_OTHER); - error = chown(fpath, -1, GID_OWNER); - if (error == 0) { - warnx("chown(%s, -1, %d) succeeded as !root, non-owner", - fpath, GID_OWNER); - goto out; - } - if (errno != EPERM) { - warn("chown(%s, -1, %d) wrong errno %d as !root, non-owner", - fpath, GID_OWNER, errno); - goto out; - } - set_euid(UID_ROOT); - (void)unlink(fpath); +/* + * Check that changing the gid of a file owned by the user is not allowed + * without privilege if the gid doesn't match the process. + */ +int +priv_vfs_chown_othergid_setup(int asroot, int injail, struct test *test) +{ /* - * Check that we can't change the uid of the file without privilege, - * even though we own the file. - */ - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - set_euid(UID_OWNER); - error = chown(fpath, UID_OTHER, -1); - if (error == 0) { - warnx("chown(%s, %d, -1) succeeded as !root", fpath, - UID_OTHER); - goto out; - } - if (errno != EPERM) { - warn("chown(%s, %d, -1) wrong errno %d as !root", fpath, - UID_OTHER, errno); - goto out; - } - set_euid(UID_ROOT); - (void)unlink(fpath); - - /* - * Check that can't change the file group to one we are not a member - * of when running without privilege. + * Create a file with a matching uid to the test process with a + * matching gid. */ - setup_file(fpath, UID_OWNER, GID_OWNER, 0600); - set_euid(UID_OWNER); + setup_file("priv_vfs_chown_othergid: fpath", fpath, asroot ? UID_ROOT + : UID_OWNER, asroot ? GID_WHEEL : GID_OWNER, 0600); + fpath_initialized = 1; + return (0); +} + +void +priv_vfs_chown_othergid(int asroot, int injail, struct test *test) +{ + int error; + error = chown(fpath, -1, GID_OTHER); - if (error == 0) { - warn("chown(%s, -1, %d) succeeded as !root", fpath, GID_OTHER); - goto out; - } - if (errno != EPERM) { - warn("chown(%s, -1, %d) wrong errno %d as !root", fpath, - errno, GID_OTHER); - goto out; + if (asroot && injail) + expect("priv_vfs_chown_othergid(root, jail)", error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_chown_othergid(root, !jail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_chown_othergid(!root, !jail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_vfs_chown_othergid(!root, !jail)", error, -1, + EPERM); +} + +void +priv_vfs_chown_cleanup(int asroot, int injail, struct test *test) +{ + + if (fpath_initialized) { + (void)unlink(fpath); + fpath_initialized = 0; } - set_euid(UID_ROOT); - (void)unlink(fpath); -out: - (void)seteuid(UID_ROOT); - (void)unlink(fpath); } diff --git a/tools/regression/priv/priv_vfs_chroot.c b/tools/regression/priv/priv_vfs_chroot.c index 06c36d4..4ba15e5 100644 --- a/tools/regression/priv/priv_vfs_chroot.c +++ b/tools/regression/priv/priv_vfs_chroot.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,8 +31,7 @@ */ /* - * Test that chroot() requires privilege; try with, and without. Do a no-op - * chroot() to "/". + * Test that chroot() requires privilege--do a no-op chroot() to "/". * * XXXRW: Would also be good to check fchroot() permission, but that is not * exposed via the BSD API. @@ -43,21 +43,31 @@ #include "main.h" +int +priv_vfs_chroot_setup(int asroot, int injail, struct test *test) +{ + + return (0); +} + void -priv_vfs_chroot(void) +priv_vfs_chroot(int asroot, int injail, struct test *test) { int error; - assert_root(); - - if (chroot("/") < 0) - err(-1, "chroot(\"/\") as root"); + error = chroot("/"); + if (asroot && injail) + expect("priv_vfs_chroot(asroot, injail)", error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_chroot(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_chroot(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_vfs_chroot(!asroot, !injail)", error, -1, EPERM); +} - set_euid(UID_OTHER); +void +priv_vfs_chroot_cleanup(int asroot, int injail, struct test *test) +{ - error = chroot("/"); - if (error == 0) - errx(-1, "chroot(\"/\") succeeded as !root"); - if (errno != EPERM) - err(-1, "chroot(\"/\") wrong errno %d as !root", errno); } diff --git a/tools/regression/priv/priv_vfs_clearsugid.c b/tools/regression/priv/priv_vfs_clearsugid.c index a8ddcd5..b62a928 100644 --- a/tools/regression/priv/priv_vfs_clearsugid.c +++ b/tools/regression/priv/priv_vfs_clearsugid.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -31,16 +32,21 @@ /* * There are three cases in which the file system will clear the setuid or - * setgid bits on a file when running as !root: + * setgid bits on a file when running unprivileged: * * - When the file is chown()'d and either of the uid or the gid is changed. + * (currently, only changing the file gid applies, as privilege is required + * to change the uid). * - * - The file is written to succeesfully. + * - The file is written to successfully. * * - An extended attribute of the file is written to successfully. * - * Test each case first as root (that flags aren't cleared), and then as - * !root, to check they are cleared. + * In each case, check that the flags are cleared if unprivileged, and that + * they aren't cleared if privileged. + * + * We can't use expect() as we're looking for side-effects rather than + * success/failure of the system call. */ #include @@ -55,161 +61,92 @@ #include "main.h" -static const gid_t gidset[] = {GID_WHEEL, GID_OWNER, GID_OTHER}; +static char fpath[1024]; +static int fpath_initialized; /* - * Confirm that the setuid bit is set on a file. Don't return on failure. + * If running as root, check that SUID is still set; otherwise, check that it + * is not. */ static void -confirm_setuid(char *fpathp, char *test_case) +confirm_sugid(char *test_case, int asroot, int injail) { struct stat sb; - if (stat(fpathp, &sb) < 0) { - warn("%s stat(%s)", test_case, fpathp); - (void)seteuid(UID_ROOT); - (void)unlink(fpathp); - exit(-1); + if (stat(fpath, &sb) < 0) { + warn("%s stat(%s)", test_case, fpath); + return; } - if (!(sb.st_mode & S_ISUID)) { - warnx("case %s stat(%s) not setuid", test_case, fpathp); - (void)seteuid(UID_ROOT); - (void)unlink(fpathp); - exit(-1); + if (asroot) { + if (!(sb.st_mode & S_ISUID)) + warnx("%s(root, %s): !SUID", test_case, injail ? + "jail" : "!jail"); + } else { + if (sb.st_mode & S_ISUID) + warnx("%s(!root, %s): SUID", test_case, injail ? + "jail" : "!jail"); } } -/* - * Confirm that the setuid bit is not set on a file. Don't return on failure. - */ -static void -confirm_notsetuid(char *fpathp, char *test_case) +int +priv_vfs_clearsugid_setup(int asroot, int injail, struct test *test) { - struct stat sb; - if (stat(fpathp, &sb) < 0) { - warn("%s stat(%s)", test_case, fpathp); - (void)seteuid(UID_ROOT); - (void)unlink(fpathp); - exit(-1); - } - if (sb.st_mode & S_ISUID) { - warnx("case %s stat(%s) is setuid", test_case, fpathp); - (void)seteuid(UID_ROOT); - (void)unlink(fpathp); - exit(-1); - } + setup_file("priv_vfs_clearsugid_setup: fpath", fpath, UID_OWNER, + GID_OTHER, 0600 | S_ISUID); + fpath_initialized = 1; + return (0); +} + +void +priv_vfs_clearsugid_chgrp(int asroot, int injail, struct test *test) +{ + + if (chown(fpath, -1, asroot ? GID_WHEEL : GID_OWNER) < 0) + err(-1, "priv_vfs_clearsugid_chgrp(%s, %s): chrgrp", + asroot ? "root" : "!root", injail ? "jail" : "!jail"); + confirm_sugid("priv_vfs_clearsugid_chgrp", asroot, injail); } #define EA_NAMESPACE EXTATTR_NAMESPACE_USER #define EA_NAME "clearsugid" #define EA_DATA "test" #define EA_SIZE (strlen(EA_DATA)) + void -priv_vfs_clearsugid(void) +priv_vfs_clearsugid_extattr(int asroot, int injail, struct test *test) { - char ch, fpath[1024]; - int fd; - assert_root(); - - /* - * Before starting on work, set up group IDs so that the process can - * change the group ID of the file without privilege, in order to see - * the effects. That way privilege is only required to maintain the - * setuid bit. For the chown() test, we change only the group id, as - * that can be done with or without privilege. - */ - if (setgroups(3, gidset) < 0) - err(-1, "setgroups(2, {%d, %d})", GID_WHEEL, GID_OWNER); - - /* - * chown() with privilege. - */ - setup_file(fpath, UID_ROOT, GID_WHEEL, 0600 | S_ISUID); - if (chown(fpath, -1, GID_OTHER) < 0) - warn("chown(%s, -1, %d) as root", fpath, GID_OTHER); - confirm_setuid(fpath, "chown as root"); - (void)unlink(fpath); - - /* - * write() with privilege. - */ - setup_file(fpath, UID_ROOT, GID_WHEEL, 0600 | S_ISUID); - fd = open(fpath, O_RDWR); - if (fd < 0) { - warn("open(%s) as root", fpath); - goto out; - } - ch = 0; - if (write(fd, &ch, sizeof(ch)) < 0) { - warn("write(%s) as root", fpath); - goto out; - } - close(fd); - confirm_setuid(fpath, "write as root"); - (void)unlink(fpath); - - /* - * extwrite() with privilege. - */ - setup_file(fpath, UID_ROOT, GID_WHEEL, 0600 | S_ISUID); if (extattr_set_file(fpath, EA_NAMESPACE, EA_NAME, EA_DATA, EA_SIZE) - < 0) { - warn("extattr_set_file(%s, user, %s, %s, %d) as root", - fpath, EA_NAME, EA_DATA, EA_SIZE); - goto out; - } - confirm_setuid(fpath, "extwrite as root"); - (void)unlink(fpath); - - /* - * chown() without privilege. - */ - setup_file(fpath, UID_OWNER, GID_OWNER, 0600 | S_ISUID); - set_euid(UID_OWNER); - if (chown(fpath, -1, GID_OTHER) < 0) - warn("chown(%s, -1, %d) as !root", fpath, GID_OTHER); - set_euid(UID_ROOT); - confirm_notsetuid(fpath, "chown as !root"); - (void)unlink(fpath); - - /* - * write() without privilege. - */ - setup_file(fpath, UID_OWNER, GID_OWNER, 0600 | S_ISUID); - set_euid(UID_OWNER); + < 0) + err(-1, + "priv_vfs_clearsugid_extattr(%s, %s): extattr_set_file", + asroot ? "root" : "!root", injail ? "jail" : "!jail"); + confirm_sugid("priv_vfs_clearsugid_extattr", asroot, injail); +} + +void +priv_vfs_clearsugid_write(int asroot, int injail, struct test *test) +{ + int fd; + fd = open(fpath, O_RDWR); - if (fd < 0) { - warn("open(%s) as !root", fpath); - goto out; - } - ch = 0; - if (write(fd, &ch, sizeof(ch)) < 0) { - warn("write(%s) as !root", fpath); - goto out; - } - close(fd); - set_euid(UID_ROOT); - confirm_notsetuid(fpath, "write as !root"); - (void)unlink(fpath); - - /* - * extwrite() without privilege. - */ - setup_file(fpath, UID_OWNER, GID_OWNER, 0600 | S_ISUID); - set_euid(UID_OWNER); - if (extattr_set_file(fpath, EA_NAMESPACE, EA_NAME, EA_DATA, EA_SIZE) - < 0) { - warn("extattr_set_file(%s, user, %s, %s, %d) as !root", - fpath, EA_NAME, EA_DATA, EA_SIZE); - goto out; - } - set_euid(UID_ROOT); - confirm_notsetuid(fpath, "extwrite as !root"); - (void)unlink(fpath); + if (fd < 0) + err(-1, "priv_vfs_clearsugid_write(%s, %s): open", + asroot ? "root" : "!root", injail ? "jail" : "!jail"); + if (write(fd, EA_DATA, EA_SIZE) < 0) + err(-1, "priv_vfs_clearsugid_write(%s, %s): write", + asroot ? "root" : "!root", injail ? "jail" : "!jail"); + (void)close(fd); + confirm_sugid("priv_vfs_clearsugid_write", asroot, injail); +} -out: - (void)seteuid(UID_ROOT); - (void)unlink(fpath); +void +priv_vfs_clearsugid_cleanup(int asroot, int injail, struct test *test) +{ + + if (fpath_initialized) { + (void)unlink(fpath); + fpath_initialized = 0; + } } diff --git a/tools/regression/priv/priv_vfs_extattr_system.c b/tools/regression/priv/priv_vfs_extattr_system.c index d67c550..9f8f887 100644 --- a/tools/regression/priv/priv_vfs_extattr_system.c +++ b/tools/regression/priv/priv_vfs_extattr_system.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -49,48 +50,57 @@ #define EA_DATA "test" #define EA_SIZE strlen(EA_DATA) -void -priv_vfs_extattr_system(void) -{ - char fpath[1024]; - int error; +static char fpath[1024]; +static int fpath_initialized; - assert_root(); +int +priv_vfs_extattr_system_setup(int asroot, int injail, struct test *test) +{ /* * Set file perms so that discretionary access control would grant * write rights on non-system EAs on the file. */ - setup_file(fpath, UID_ROOT, GID_WHEEL, 0666); + setup_file("priv_vfs_extattr_system_setup: fpath", fpath, UID_ROOT, + GID_WHEEL, 0666); + fpath_initialized = 1; + return (0); +} - /* - * Try with privilege. - */ - if (extattr_set_file(fpath, EA_NAMESPACE, EA_NAME, EA_DATA, EA_SIZE) - < 0) { - warn("extattr_set_file(SYSTEM, %s, %s, %d) as root", - EA_NAME, EA_DATA, EA_SIZE); - goto out; - } +void +priv_vfs_extattr_system(int asroot, int injail, struct test *test) +{ + ssize_t ret; + int error; - set_euid(UID_OTHER); + ret = extattr_set_file(fpath, EA_NAMESPACE, EA_NAME, EA_DATA, + EA_SIZE); + if (ret < 0) + error = -1; + else if (ret == EA_SIZE) + error = 0; + else + err(-1, "priv_vfs_extattr_system: set returned %d", ret); + if (asroot && injail) + expect("priv_vfs_extattr_system(asroot, injail)", error, -1, + EPERM); + if (asroot && !injail) + expect("priv_vfs_extattr_system(asroot, !injail)", error, 0, + 0); + if (!asroot && injail) + expect("priv_vfs_extattr_system(!asroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_vfs_extattr_system(!asroot, !injail)", error, + -1, EPERM); +} - /* - * Try without privilege. - */ - error = extattr_set_file(fpath, EA_NAMESPACE, EA_NAME, EA_DATA, - EA_SIZE); - if (error == 0) { - warn("extattr_set_file(SYSTEM, %s, %s, %d) succeeded as !root", - EA_NAME, EA_DATA, EA_SIZE); - goto out; - } - if (errno != EPERM) { - warn("extattr_set_file(SYSTEM, %s, %s, %d) wrong errno %d " - "as !root", EA_NAME, EA_DATA, EA_SIZE, errno); - goto out; +void +priv_vfs_extattr_system_cleanup(int asroot, int injail, struct test *test) +{ + + if (fpath_initialized) { + (void)unlink(fpath); + fpath_initialized = 0; } -out: - seteuid(UID_ROOT); - (void)unlink(fpath); } diff --git a/tools/regression/priv/priv_vfs_fhopen.c b/tools/regression/priv/priv_vfs_fhopen.c index cb4006d..32b32f9 100644 --- a/tools/regression/priv/priv_vfs_fhopen.c +++ b/tools/regression/priv/priv_vfs_fhopen.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,9 +31,8 @@ */ /* - * Confirm that calls to fhopen() require privilege, trying with, and - * without. We create a temporary file and grab the file handle using - * getfh() before starting. + * Confirm that calls to fhopen() require non-jailed priilege. We create a + * temporary file and grab the file handle using getfh() before starting. */ #include @@ -45,48 +45,53 @@ #include "main.h" -void -priv_vfs_fhopen(void) -{ - char fpath[1024]; - fhandle_t fh; - int fd; +static char fpath[1024]; +static int fpath_initialized; +static fhandle_t fh; - assert_root(); - - setup_file(fpath, UID_ROOT, GID_WHEEL, 0644); +int +priv_vfs_fhopen_setup(int asroot, int injail, struct test *test) +{ + setup_file("private_vfs_fhopen_setup: fpath", fpath, UID_ROOT, + GID_WHEEL, 0644); + fpath_initialized = 1; if (getfh(fpath, &fh) < 0) { - warn("getfh(%s)", fpath); - goto out; + warn("priv_vfs_fhopen_setup: getfh(%s)", fpath); + return (-1); } + return (0); +} - /* - * First, try with privilege. - */ - fd = fhopen(&fh, O_RDONLY); - if (fd < 0) { - warn("fhopen(%s) as root", fpath); - goto out; - } - close(fd); - - /* - * Now, without privilege. - */ - set_euid(UID_OTHER); +void +priv_vfs_fhopen(int asroot, int injail, struct test *test) +{ + int errno_saved, error, fd; fd = fhopen(&fh, O_RDONLY); if (fd >= 0) { - warnx("fhopen(%s) succeeded as !root", fpath); + error = 0; + errno_saved = errno; close(fd); - goto out; - } - if (errno != EPERM) { - warn("fhopen(%s) wrong errno %d as !root", fpath, errno); - goto out; + errno = errno_saved; + } else + error = -1; + if (asroot && injail) + expect("priv_vfs_fhopen(asroot, injail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_vfs_fhopen(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_fhopen(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_vfs_fhopen(!asroot, !injail)", error, -1, EPERM); +} + +void +priv_vfs_fhopen_cleanup(int asroot, int injail, struct test *test) +{ + + if (fpath_initialized) { + (void)unlink(fpath); + fpath_initialized = 0; } -out: - seteuid(UID_ROOT); - (void)unlink(fpath); } diff --git a/tools/regression/priv/priv_vfs_fhstat.c b/tools/regression/priv/priv_vfs_fhstat.c index c8e58e8..18506fa 100644 --- a/tools/regression/priv/priv_vfs_fhstat.c +++ b/tools/regression/priv/priv_vfs_fhstat.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,9 +31,8 @@ */ /* - * Confirm that calls to fhstat() require privilege, trying with, and - * without. We create a temporary file and grab the file handle using - * getfh() before starting. + * Confirm that calls to fhstat() require non-jailed privilege. We create a + * temporary file and grab the file handle using getfh() before starting. */ #include @@ -45,45 +45,47 @@ #include "main.h" -void -priv_vfs_fhstat(void) -{ - char fpath[1024]; - struct stat sb; - fhandle_t fh; - int error; - - assert_root(); +static char fpath[1024]; +static int fpath_initialized; +static fhandle_t fh; - setup_file(fpath, UID_ROOT, GID_WHEEL, 0644); +int +priv_vfs_fhstat_setup(int asroot, int injail, struct test *test) +{ + setup_file("priv_vfs_fhstat_setup: fpath", fpath, UID_ROOT, + GID_WHEEL, 0644); + fpath_initialized = 1; if (getfh(fpath, &fh) < 0) { - warn("getfh(%s)", fpath); - goto out; + warn("priv_vfs_fhstat_setup: getfh(%s)", fpath); + return (-1); } + return (0); +} - /* - * First, try with privilege. - */ - if (fhstat(&fh, &sb) < 0) { - warn("fhstat(%s) as root", fpath); - goto out; - } +void +priv_vfs_fhstat(int asroot, int injail, struct test *test) +{ + struct stat sb; + int error; - /* - * Now, without privilege. - */ - set_euid(UID_OTHER); error = fhstat(&fh, &sb); - if (error == 0) { - warn("fhstat(%s) succeeded as !root", fpath); - goto out; - } - if (errno != EPERM) { - warn("fhstat(%s) wrong errno %d as !root", fpath, errno); - goto out; + if (asroot && injail) + expect("priv_vfs_fhstat(asroot, injail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_vfs_fhstat(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_fhstat(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_vfs_fhstat(!asroot, !injail)", error, -1, EPERM); +} + +void +priv_vfs_fhstat_cleanup(int asroot, int injail, struct test *test) +{ + + if (fpath_initialized) { + (void)unlink(fpath); + fpath_initialized = 0; } -out: - seteuid(UID_ROOT); - (void)unlink(fpath); } diff --git a/tools/regression/priv/priv_vfs_fhstatfs.c b/tools/regression/priv/priv_vfs_fhstatfs.c index 4709fe2..f814989 100644 --- a/tools/regression/priv/priv_vfs_fhstatfs.c +++ b/tools/regression/priv/priv_vfs_fhstatfs.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,9 +31,8 @@ */ /* - * Confirm that calls to fhstatfs() require privilege, trying with, and - * without. We create a temporary file and grab the file handle using - * getfh() before starting. + * Confirm that calls to fhstatfs() require non-jailed privilege. We create + * a temporary file and grab the file handle using getfh() before starting. */ #include @@ -44,46 +44,50 @@ #include "main.h" -void -priv_vfs_fhstatfs(void) -{ - char fpath[1024]; - struct statfs sf; - fhandle_t fh; - int error; - - assert_root(); +static char fpath[1024]; +static int fpath_initialized; +static fhandle_t fh; - setup_file(fpath, UID_ROOT, GID_WHEEL, 0644); +int +priv_vfs_fhstatfs_setup(int asroot, int injail, struct test *test) +{ + setup_file("priv_vfs_fhstatfs_setup: fpath", fpath, UID_ROOT, + GID_WHEEL, 0644); + fpath_initialized = 1; if (getfh(fpath, &fh) < 0) { - warn("getfh(%s)", fpath); - goto out; - } - - /* - * First, try with privilege. - */ - if (fhstatfs(&fh, &sf) < 0) { - warn("fhstatfs(%s) as root", fpath); - goto out; + warn("priv_vfs_fhstatfs_setup: getfh(%s)", fpath); + return (-1); } + return (0); +} - /* - * Now, without privilege. - */ - set_euid(UID_OTHER); +void +priv_vfs_fhstatfs(int asroot, int injail, struct test *test) +{ + struct statfs sf; + int error; error = fhstatfs(&fh, &sf); - if (error == 0) { - warnx("fhstatfs(%s) succeeded as !root", fpath); - goto out; - } - if (errno != EPERM) { - warn("fhstatfs(%s) wrong errno %d as !root", fpath, errno); - goto out; + if (asroot && injail) + expect("priv_vfs_fhstatfs(asroot, injail)", error, -1, + EPERM); + if (asroot && !injail) + expect("priv_vfs_fhstatfs(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_fhstatfs(!asroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_vfs_fhstatfs(!asroot, !injail)", error, -1, + EPERM); +} + +void +priv_vfs_fhstatfs_cleanup(int asroot, int injail, struct test *test) +{ + + if (fpath_initialized) { + (void)unlink(fpath); + fpath_initialized = 0; } -out: - seteuid(UID_ROOT); - (void)unlink(fpath); } diff --git a/tools/regression/priv/priv_vfs_generation.c b/tools/regression/priv/priv_vfs_generation.c index 2ccca79..0ac58c5 100644 --- a/tools/regression/priv/priv_vfs_generation.c +++ b/tools/regression/priv/priv_vfs_generation.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -33,8 +34,8 @@ * Confirm that a generation number isn't returned by stat() when not running * with privilege. In order to differentiate between a generation of 0 and * a generation not being returned, we have to create a temporary file known - * to have a non-0 generation. We try up to 10 times, and then give up, - * which is non-ideal, but better than not testing for a problem. + * to have a non-0 generation. We try up to MAX_TRIES times, and then give + * up, which is non-ideal, but better than not testing for a problem. */ #include @@ -46,68 +47,74 @@ #include "main.h" -/* - * Can't use setup_file() since the resulting file needs to have specific - * properties. - */ -void -priv_vfs_generation(void) +static char fpath[1024]; +static int fpath_initialized; + +#define MAX_TRIES 100 + +int +priv_vfs_generation_setup(int asroot, int injail, struct test *test) { - char fpath[1024] = "/tmp/priv.XXXXXXXXXX"; struct stat sb; - int fd, i; - - assert_root(); + int i; /* - * Create a file with a non-0 generation number. Try ten times, - * which gives a high chance of succeeds, fail otherwise. Not ideal, - * since we can't distinguish the file having a generation of 0 from - * not being able to query it for access control reasons. The perils - * of an API that changes behavior based on lack of privilege rather - * than failing... + * The kernel zeros the generation number field when an unprivileged + * user stats a file. In order to distinguish the two cases, we + * therefore require a file that we know has a non-zero generation + * number. We try up to MAX_TRIES times and otherwise fail. */ - for (i = 0; i < 10; i++) { - fd = mkstemp(fpath); - if (fd < 0) - err(-1, "mkstemp"); - if (fstat(fd, &sb) < 0) { - warn("fstat(%s)", fpath); - close(fd); - goto out; + for (i = 0; i < MAX_TRIES; i++) { + setup_file("priv_vfs_generation_setup: fpath", fpath, + UID_ROOT, GID_WHEEL, 0644); + if (stat(fpath, &sb) < 0) { + warn("priv_vfs_generation_setup: fstat(%s)", fpath); + (void)unlink(fpath); + return (-1); + } + if (sb.st_gen != 0) { + fpath_initialized = 1; + return (0); } - if (sb.st_gen != 0) - break; - close(fd); - (void)unlink(fpath); - strcpy(fpath, "/tmp/generation.XXXXXXXXXX"); - fd = -1; } - if (fd == -1) - errx(-1, - "could not create file with non-0 generation as root"); - close(fd); + warnx("priv_vfs_generation_setup: unable to create gen file"); + return (-1); +} - /* - * We've already tested that fstat() works, but try stat() to be - * consistent between privileged and unprivileged tests. - */ - if (stat(fpath, &sb) < 0) { - warn("stat(%s) as root", fpath); - goto out; - } +void +priv_vfs_generation(int asroot, int injail, struct test *test) +{ + struct stat sb; + int error; - set_euid(UID_OTHER); + error = stat(fpath, &sb); + if (error < 0) + warn("priv_vfs_generation(asroot, injail) stat"); - if (stat(fpath, &sb) < 0) { - warn("stat(%s) as !root", fpath); - goto out; - } + if (sb.st_gen == 0) { + error = -1; + errno = EPERM; + } else + error = 0; + if (asroot && injail) + expect("priv_vfs_generation(asroot, injail)", error, -1, + EPERM); + if (asroot && !injail) + expect("priv_vfs_generation(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_generation(!asroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_vfs_generation(!asroot, !injail)", error, -1, + EPERM); +} - if (sb.st_gen != 0) - warn("stat(%s) returned generation as !root", fpath); +void +priv_vfs_generation_cleanup(int asroot, int injail, struct test *test) +{ -out: - (void)seteuid(UID_ROOT); - (void)unlink(fpath); + if (fpath_initialized) { + (void)unlink(fpath); + fpath_initialized = 0; + } } diff --git a/tools/regression/priv/priv_vfs_getfh.c b/tools/regression/priv/priv_vfs_getfh.c index ff5d6fe..d2904df 100644 --- a/tools/regression/priv/priv_vfs_getfh.c +++ b/tools/regression/priv/priv_vfs_getfh.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,8 +31,7 @@ */ /* - * Check that getfh() requires privilege; run it with, and without, - * privilege. + * Check that getfh() requires non-jailed privilege. */ #include @@ -43,36 +43,37 @@ #include "main.h" +static char fpath[1024]; + +int +priv_vfs_getfh_setup(int asroot, int injail, struct test *test) +{ + + setup_file("priv_vfs_getfh_setup: fpath", fpath, UID_ROOT, GID_WHEEL, + 0644); + return (0); +} + void -priv_vfs_getfh(void) +priv_vfs_getfh(int asroot, int injail, struct test *test) { - char fpath[1024]; fhandle_t fh; int error; - assert_root(); - - setup_file(fpath, UID_ROOT, GID_WHEEL, 0644); - - if (getfh(fpath, &fh) < 0) { - warn("getfh(%s) as root", fpath); - goto out; - } - - set_euid(UID_OTHER); - error = getfh(fpath, &fh); - if (error == 0) { - warnx("getfh(%s) succeeded as !root", fpath); - goto out; - } + if (asroot && injail) + expect("priv_vfs_getfh(asroot, injail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_vfs_getfh(asroot, !injail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_getfh(!asroot, injail)", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_vfs_getfh(!asroot, !injail)", error, -1, EPERM); +} - if (errno != EPERM) { - warn("getfh(%s) wrong errno %d as !root", fpath, errno); - goto out; - } +void +priv_vfs_getfh_cleanup(int asroot, int injail, struct test *test) +{ -out: - (void)seteuid(UID_ROOT); (void)unlink(fpath); } diff --git a/tools/regression/priv/priv_vfs_read_write.c b/tools/regression/priv/priv_vfs_read_write.c index c7f479d..5bf5a03 100644 --- a/tools/regression/priv/priv_vfs_read_write.c +++ b/tools/regression/priv/priv_vfs_read_write.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -47,324 +48,212 @@ #include "main.h" -struct test_arguments { - int open_flags; - uid_t proc_uid; - gid_t proc_gid; - uid_t file_uid; - gid_t file_gid; -}; +static char fpath_none[1024]; +static char fpath_read[1024]; +static char fpath_write[1024]; +static char fpath_readwrite[1024]; -/* - * Rather special-purpose, don't reuse. Will need updating if anything other - * than O_RDONLY and O_WRONLY are to be used in tests. - */ -static const char * -flags_to_string(int flags) -{ - - switch (flags) { - case O_RDONLY: - return ("O_RDONLY"); - - case O_WRONLY: - return ("O_WRONLY"); - - default: - return ("unknown"); - } -} +static int fpath_none_initialized; +static int fpath_read_initialized; +static int fpath_write_initialized; +static int fpath_readwrite_initialized; static void -test_perm(struct test_arguments ta, mode_t file_mode, int expected) +try_io(const char *label, const char *fpathp, int asroot, int injail, + int flags, int expected_error, int expected_errno) { - uid_t proc_uid, file_uid; - gid_t proc_gid, file_gid; - int fd, open_flags; - char fpath[1024]; - - proc_uid = ta.proc_uid; - proc_gid = ta.proc_gid; - file_uid = ta.file_uid; - file_gid = ta.file_gid; - open_flags = ta.open_flags; - - setup_file(fpath, file_uid, file_gid, file_mode); - set_creds(proc_uid, proc_gid); - - fd = open(fpath, open_flags); - - if (expected == 0) { - if (fd <= 0) { - warn("test_perm(%s, %d, %d, %d, %d, %04o, %d) " - "returned %d instead of %d", - flags_to_string(open_flags), proc_uid, proc_gid, - file_uid, file_gid, file_mode, expected, - errno, expected); - restore_creds(); - (void)unlink(fpath); - exit(-1); - } - close(fd); + int fd; + + fd = open(fpathp, flags); + if (fd < 0) { + if (expected_error != -1) + warnx("%s(%s, %s): expected (%d, %d) got (-1, %d)", + label, asroot ? "root" : "!root", injail ? "jail" + : "!jail", expected_error, expected_errno, errno); } else { - if (fd >= 0) { - warnx("test_perm(%s, %d, %d, %d, %d, %04o, %d)" - " returned 0 instead of %d", - flags_to_string(open_flags), proc_uid, proc_gid, - file_uid, file_gid, file_mode, expected, - expected); - close(fd); - restore_creds(); - (void)unlink(fpath); - exit(-1); - } else if (errno != expected) { - warn("test_perm(%s, %d, %d, %d, %d, %04o, %d)" - " returned %d instead of %d", - flags_to_string(open_flags), proc_uid, proc_gid, - file_uid, file_gid, file_mode, expected, - errno, expected); - restore_creds(); - (void)unlink(fpath); - exit(-1); - } + if (expected_error == -1) + warnx("%s(%s, %s): expected (%d, %d) got 0", label, + asroot ? "root" : "!root", injail ? "jail" : + "!jail", expected_error, expected_errno); + (void)close(fd); } - - restore_creds(); - (void)unlink(fpath); } -static const gid_t gidset[] = { GID_WHEEL }; - -static void -preamble(void) +int +priv_vfs_readwrite_fowner_setup(int asroot, int injail, struct test *test) { - if (getuid() != UID_ROOT) - errx(-1, "must be run as root"); - if (setgroups(1, gidset) < 0) - err(-1, "setgroups(1, {%d})", GID_WHEEL); + setup_file("priv_vfs_readwrite_fowner_setup: fpath_none", fpath_none, + asroot ? UID_ROOT : UID_OWNER, GID_OTHER, 0000); + fpath_none_initialized = 1; + setup_file("priv_vfs_readwrite_fowner_setup: fpath_read", fpath_read, + asroot ? UID_ROOT : UID_OWNER, GID_OTHER, 0400); + fpath_read_initialized = 1; + setup_file("priv_vfs_readwrite_fowner_setup: fpath_write", + fpath_write, asroot ? UID_ROOT : UID_OWNER, GID_OTHER, 0200); + fpath_write_initialized = 1; + setup_file("priv_vfs_readwrite_fowner_setup: fpath_readwrite", + fpath_readwrite, asroot ? UID_ROOT : UID_OWNER, GID_OTHER, 0600); + fpath_readwrite_initialized = 1; + return (0); } -void -priv_vfs_read(void) +int +priv_vfs_readwrite_fgroup_setup(int asroot, int injail, struct test *test) { - struct test_arguments ta; - - preamble(); - - ta.open_flags = O_RDONLY; - - /* - * Privileged user and file owner. All tests should pass. - */ - ta.proc_uid = UID_ROOT; - ta.proc_gid = GID_WHEEL; - ta.file_uid = UID_ROOT; - ta.file_gid = GID_WHEEL; - - test_perm(ta, 0000, 0); - test_perm(ta, 0100, 0); - test_perm(ta, 0200, 0); - test_perm(ta, 0300, 0); - test_perm(ta, 0400, 0); - test_perm(ta, 0500, 0); - test_perm(ta, 0600, 0); - test_perm(ta, 0700, 0); - - /* - * Privileged user and file group. All tests should pass. - */ - ta.proc_uid = UID_ROOT; - ta.proc_gid = GID_WHEEL; - ta.file_uid = UID_OWNER; - ta.file_gid = GID_WHEEL; - - test_perm(ta, 0000, 0); - test_perm(ta, 0010, 0); - test_perm(ta, 0020, 0); - test_perm(ta, 0030, 0); - test_perm(ta, 0040, 0); - test_perm(ta, 0050, 0); - test_perm(ta, 0060, 0); - test_perm(ta, 0070, 0); - - /* - * Privileged user and file other. All tests should pass. - */ - ta.proc_uid = UID_ROOT; - ta.proc_gid = GID_WHEEL; - ta.file_uid = UID_OWNER; - ta.file_gid = GID_OWNER; - - test_perm(ta, 0000, 0); - test_perm(ta, 0001, 0); - test_perm(ta, 0002, 0); - test_perm(ta, 0003, 0); - test_perm(ta, 0004, 0); - test_perm(ta, 0005, 0); - test_perm(ta, 0006, 0); - test_perm(ta, 0007, 0); - - /* - * Unprivileged user and file owner. Various DAC failures. - */ - ta.proc_uid = UID_OWNER; - ta.proc_gid = GID_OWNER; - ta.file_uid = UID_OWNER; - ta.file_gid = GID_OWNER; - test_perm(ta, 0000, EACCES); - test_perm(ta, 0100, EACCES); - test_perm(ta, 0200, EACCES); - test_perm(ta, 0300, EACCES); - test_perm(ta, 0400, 0); - test_perm(ta, 0500, 0); - test_perm(ta, 0600, 0); - test_perm(ta, 0700, 0); - - /* - * Unprivileged user and file group. Various DAC failures. - */ - ta.proc_uid = UID_OTHER; - ta.proc_gid = GID_OWNER; - ta.file_uid = UID_OWNER; - ta.file_gid = GID_OWNER; - - test_perm(ta, 0000, EACCES); - test_perm(ta, 0010, EACCES); - test_perm(ta, 0020, EACCES); - test_perm(ta, 0030, EACCES); - test_perm(ta, 0040, 0); - test_perm(ta, 0050, 0); - test_perm(ta, 0060, 0); - test_perm(ta, 0070, 0); + setup_file("priv_vfs_readwrite_fgroup_setup: fpath_none", fpath_none, + UID_OTHER, asroot ? GID_WHEEL : GID_OWNER, 0000); + fpath_none_initialized = 1; + setup_file("priv_vfs_readwrite_fgroup_setup: fpath_read", fpath_read, + UID_OTHER, asroot ? GID_WHEEL : GID_OWNER, 0040); + fpath_read_initialized = 1; + setup_file("priv_vfs_readwrite_fgroup_setup: fpath_write", + fpath_write, UID_OTHER, asroot ? GID_WHEEL : GID_OWNER, 0020); + fpath_write_initialized = 1; + setup_file("priv_vfs_readwrite_fgroup_setup: fpath_readwrite", + fpath_readwrite, UID_OTHER, asroot ? GID_WHEEL : GID_OWNER, + 0060); + fpath_readwrite_initialized = 1; + return (0); +} - /* - * Unprivileged user and file other. Various DAC failures. - */ - ta.proc_uid = UID_OTHER; - ta.proc_gid = GID_OTHER; - ta.file_uid = UID_OWNER; - ta.file_gid = GID_OWNER; +int +priv_vfs_readwrite_fother_setup(int asroot, int injail, struct test *test) +{ - test_perm(ta, 0000, EACCES); - test_perm(ta, 0001, EACCES); - test_perm(ta, 0002, EACCES); - test_perm(ta, 0003, EACCES); - test_perm(ta, 0004, 0); - test_perm(ta, 0005, 0); - test_perm(ta, 0006, 0); - test_perm(ta, 0007, 0); + setup_file("priv_vfs_readwrite_fother_setup: fpath_none", fpath_none, + UID_OTHER, GID_OTHER, 0000); + fpath_none_initialized = 1; + setup_file("priv_vfs_readwrite_fother_setup: fpath_read", fpath_read, + UID_OTHER, GID_OTHER, 0004); + fpath_read_initialized = 1; + setup_file("priv_vfs_readwrite_fother_setup: fpath_write", + fpath_write, UID_OTHER, GID_OTHER, 0002); + fpath_write_initialized = 1; + setup_file("priv_vfs_readwrite_fother_setup: fpath_readwrite", + fpath_readwrite, UID_OTHER, GID_OTHER, 0006); + fpath_readwrite_initialized = 1; + return (0); } void -priv_vfs_write(void) +priv_vfs_readwrite_fowner(int asroot, int injail, struct test *test) { - struct test_arguments ta; - - preamble(); - - ta.open_flags = O_WRONLY; - /* - * Privileged user and file owner. All tests should pass. - */ - ta.proc_uid = UID_ROOT; - ta.proc_gid = GID_WHEEL; - ta.file_uid = UID_ROOT; - ta.file_gid = GID_WHEEL; - - test_perm(ta, 0000, 0); - test_perm(ta, 0100, 0); - test_perm(ta, 0200, 0); - test_perm(ta, 0300, 0); - test_perm(ta, 0400, 0); - test_perm(ta, 0500, 0); - test_perm(ta, 0600, 0); - test_perm(ta, 0700, 0); - - /* - * Privileged user and file group. All tests should pass. - */ - ta.proc_uid = UID_ROOT; - ta.proc_gid = GID_WHEEL; - ta.file_uid = UID_OWNER; - ta.file_gid = GID_WHEEL; - - test_perm(ta, 0000, 0); - test_perm(ta, 0010, 0); - test_perm(ta, 0020, 0); - test_perm(ta, 0030, 0); - test_perm(ta, 0040, 0); - test_perm(ta, 0050, 0); - test_perm(ta, 0060, 0); - test_perm(ta, 0070, 0); - - /* - * Privileged user and file other. All tests should pass. - */ - ta.proc_uid = UID_ROOT; - ta.proc_gid = GID_WHEEL; - ta.file_uid = UID_OWNER; - ta.file_gid = GID_OWNER; - - test_perm(ta, 0000, 0); - test_perm(ta, 0001, 0); - test_perm(ta, 0002, 0); - test_perm(ta, 0003, 0); - test_perm(ta, 0004, 0); - test_perm(ta, 0005, 0); - test_perm(ta, 0006, 0); - test_perm(ta, 0007, 0); + try_io("priv_vfs_readwrite_fowner(none, O_RDONLY)", fpath_none, + asroot, injail, O_RDONLY, asroot ? 0 : -1, EACCES); + try_io("priv_vfs_readwrite_fowner(none, O_WRONLY)", fpath_none, + asroot, injail, O_WRONLY, asroot ? 0 : -1, EACCES); + try_io("priv_vfs_readwrite_fowner(none, O_RDWR)", fpath_none, + asroot, injail, O_RDWR, asroot ? 0 : -1, EACCES); + + try_io("priv_vfs_readwrite_fowner(read, O_RDONLY)", fpath_read, + asroot, injail, O_RDONLY, 0, 0); + try_io("priv_vfs_readwrite_fowner(read, O_WRONLY)", fpath_read, + asroot, injail, O_WRONLY, asroot ? 0 : -1, EACCES); + try_io("priv_vfs_readwrite_fowner(read, O_RDWR)", fpath_read, + asroot, injail, O_RDWR, asroot ? 0 : -1, EACCES); + + try_io("priv_vfs_readwrite_fowner(write, O_RDONLY)", fpath_write, + asroot, injail, O_RDONLY, asroot ? 0 : -1, EACCES); + try_io("priv_vfs_readwrite_fowner(write, O_WRONLY)", fpath_write, + asroot, injail, O_WRONLY, 0, 0); + try_io("priv_vfs_readwrite_fowner(write, O_RDWR)", fpath_write, + asroot, injail, O_RDWR, asroot ? 0 : -1, EACCES); + + try_io("priv_vfs_readwrite_fowner(write, O_RDONLY)", fpath_readwrite, + asroot, injail, O_RDONLY, 0, 0); + try_io("priv_vfs_readwrite_fowner(write, O_WRONLY)", fpath_readwrite, + asroot, injail, O_WRONLY, 0, 0); + try_io("priv_vfs_readwrite_fowner(write, O_RDWR)", fpath_readwrite, + asroot, injail, O_RDWR, 0, 0); +} - /* - * Unprivileged user and file owner. Various DAC failures. - */ - ta.proc_uid = UID_OWNER; - ta.proc_gid = GID_OWNER; - ta.file_uid = UID_OWNER; - ta.file_gid = GID_OWNER; +void +priv_vfs_readwrite_fgroup(int asroot, int injail, struct test *test) +{ - test_perm(ta, 0000, EACCES); - test_perm(ta, 0100, EACCES); - test_perm(ta, 0200, 0); - test_perm(ta, 0300, 0); - test_perm(ta, 0400, EACCES); - test_perm(ta, 0500, EACCES); - test_perm(ta, 0600, 0); - test_perm(ta, 0700, 0); + try_io("priv_vfs_readwrite_fgroup(none, O_RDONLY)", fpath_none, + asroot, injail, O_RDONLY, asroot ? 0 : -1, EACCES); + try_io("priv_vfs_readwrite_fgroup(none, O_WRONLY)", fpath_none, + asroot, injail, O_WRONLY, asroot ? 0 : -1, EACCES); + try_io("priv_vfs_readwrite_fgroup(none, O_RDWR)", fpath_none, + asroot, injail, O_RDWR, asroot ? 0 : -1, EACCES); + + try_io("priv_vfs_readwrite_fgroup(read, O_RDONLY)", fpath_read, + asroot, injail, O_RDONLY, 0, 0); + try_io("priv_vfs_readwrite_fgroup(read, O_WRONLY)", fpath_read, + asroot, injail, O_WRONLY, asroot ? 0 : -1, EACCES); + try_io("priv_vfs_readwrite_fgroup(read, O_RDWR)", fpath_read, + asroot, injail, O_RDWR, asroot ? 0 : -1, EACCES); + + try_io("priv_vfs_readwrite_fgroup(write, O_RDONLY)", fpath_write, + asroot, injail, O_RDONLY, asroot ? 0 : -1, EACCES); + try_io("priv_vfs_readwrite_fgroup(write, O_WRONLY)", fpath_write, + asroot, injail, O_WRONLY, 0, 0); + try_io("priv_vfs_readwrite_fgroup(write, O_RDWR)", fpath_write, + asroot, injail, O_RDWR, asroot ? 0 : -1, EACCES); + + try_io("priv_vfs_readwrite_fgroup(write, O_RDONLY)", fpath_readwrite, + asroot, injail, O_RDONLY, 0, 0); + try_io("priv_vfs_readwrite_fgroup(write, O_WRONLY)", fpath_readwrite, + asroot, injail, O_WRONLY, 0, 0); + try_io("priv_vfs_readwrite_fgroup(write, O_RDWR)", fpath_readwrite, + asroot, injail, O_RDWR, 0, 0); +} - /* - * Unprivileged user and file group. Various DAC failures. - */ - ta.proc_uid = UID_OTHER; - ta.proc_gid = GID_OWNER; - ta.file_uid = UID_OWNER; - ta.file_gid = GID_OWNER; +void +priv_vfs_readwrite_fother(int asroot, int injail, struct test *test) +{ - test_perm(ta, 0000, EACCES); - test_perm(ta, 0010, EACCES); - test_perm(ta, 0020, 0); - test_perm(ta, 0030, 0); - test_perm(ta, 0040, EACCES); - test_perm(ta, 0050, EACCES); - test_perm(ta, 0060, 0); - test_perm(ta, 0070, 0); + try_io("priv_vfs_readwrite_fother(none, O_RDONLY)", fpath_none, + asroot, injail, O_RDONLY, asroot ? 0 : -1, EACCES); + try_io("priv_vfs_readwrite_fother(none, O_WRONLY)", fpath_none, + asroot, injail, O_WRONLY, asroot ? 0 : -1, EACCES); + try_io("priv_vfs_readwrite_fother(none, O_RDWR)", fpath_none, + asroot, injail, O_RDWR, asroot ? 0 : -1, EACCES); + + try_io("priv_vfs_readwrite_fother(read, O_RDONLY)", fpath_read, + asroot, injail, O_RDONLY, 0, 0); + try_io("priv_vfs_readwrite_fother(read, O_WRONLY)", fpath_read, + asroot, injail, O_WRONLY, asroot ? 0 : -1, EACCES); + try_io("priv_vfs_readwrite_fother(read, O_RDWR)", fpath_read, + asroot, injail, O_RDWR, asroot ? 0 : -1, EACCES); + + try_io("priv_vfs_readwrite_fother(write, O_RDONLY)", fpath_write, + asroot, injail, O_RDONLY, asroot ? 0 : -1, EACCES); + try_io("priv_vfs_readwrite_fother(write, O_WRONLY)", fpath_write, + asroot, injail, O_WRONLY, 0, 0); + try_io("priv_vfs_readwrite_fother(write, O_RDWR)", fpath_write, + asroot, injail, O_RDWR, asroot ? 0 : -1, EACCES); + + try_io("priv_vfs_readwrite_fother(write, O_RDONLY)", fpath_readwrite, + asroot, injail, O_RDONLY, 0, 0); + try_io("priv_vfs_readwrite_fother(write, O_WRONLY)", fpath_readwrite, + asroot, injail, O_WRONLY, 0, 0); + try_io("priv_vfs_readwrite_fother(write, O_RDWR)", fpath_readwrite, + asroot, injail, O_RDWR, 0, 0); +} - /* - * Unprivileged user and file other. Various DAC failures. - */ - ta.proc_uid = UID_OTHER; - ta.proc_gid = GID_OTHER; - ta.file_uid = UID_OWNER; - ta.file_gid = GID_OWNER; +void +priv_vfs_readwrite_cleanup(int asroot, int injail, struct test *test) +{ - test_perm(ta, 0000, EACCES); - test_perm(ta, 0001, EACCES); - test_perm(ta, 0002, 0); - test_perm(ta, 0003, 0); - test_perm(ta, 0004, EACCES); - test_perm(ta, 0005, EACCES); - test_perm(ta, 0006, 0); - test_perm(ta, 0007, 0); + if (fpath_none_initialized) { + (void)unlink(fpath_none); + fpath_none_initialized = 0; + } + if (fpath_read_initialized) { + (void)unlink(fpath_read); + fpath_read_initialized = 0; + } + if (fpath_write_initialized) { + (void)unlink(fpath_write); + fpath_write_initialized = 0; + } + if (fpath_readwrite_initialized) { + (void)unlink(fpath_readwrite); + fpath_readwrite_initialized = 0; + } } diff --git a/tools/regression/priv/priv_vfs_setgid.c b/tools/regression/priv/priv_vfs_setgid.c index b763ef6..62ebf8c 100644 --- a/tools/regression/priv/priv_vfs_setgid.c +++ b/tools/regression/priv/priv_vfs_setgid.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -45,99 +46,76 @@ #include "main.h" -static const gid_t gidset_without[] = {GID_WHEEL}; -static const gid_t gidset_with[] = {GID_WHEEL, GID_OWNER}; +static char fpath[1024]; +static int fpath_initialized; -void -priv_vfs_setgid(void) +int +priv_vfs_setgid_fowner_setup(int asroot, int injail, struct test *test) { - char fpath[1024]; - int error, fd; - - assert_root(); - - setup_file(fpath, UID_ROOT, GID_OWNER, 0644); - - if (setgroups(1, gidset_without) < 0) { - warn("setgroups(1, {%d})", gidset_without[0]); - goto out; - } - - fd = open(fpath, O_RDWR); - if (fd < 0) { - warn("open(%s, O_RDWR)", fpath); - goto out; - } - /* - * With privilege, set mode on file. - */ - if (fchmod(fd, 0600 | S_ISGID) < 0) { - warn("fchmod(%s, 0600 | S_ISGID) as root", fpath); - goto out; - } - - /* - * Reset mode and chown file before dropping privilege. - */ - if (fchmod(fd, 0600) < 0) { - warn("fchmod(%s, 0600) as root", fpath); - goto out; - } - - if (fchown(fd, UID_OWNER, GID_OWNER) < 0) { - warn("fchown(%s, %d, %d) as root", fpath, UID_OWNER, - GID_OTHER); - goto out; - } + setup_file("priv_vfs_setgid_fowner: fpath", fpath, UID_OWNER, + GID_OWNER, 0600); + fpath_initialized = 1; + return (0); +} - /* - * Drop privilege. - */ - set_euid(UID_OWNER); +int +priv_vfs_setgid_fother_setup(int asroot, int injail, struct test *test) +{ - /* - * Without privilege, set mode on file. - */ - error = fchmod(fd, 0600 | S_ISGID); - if (error == 0) { - warnx("fchmod(%s, 0600 | S_ISGID) succeeded as !root", - fpath); - goto out; - } - if (errno != EPERM) { - warn("fchmod(%s, 0600 | S_ISGID) wrong errno %d as !root", - fpath, errno); - goto out; - } + /* NOTE: owner uid, *other* gid. */ + setup_file("priv_vfs_setgid_forther: fpath", fpath, UID_OWNER, + GID_OTHER, 0600); + fpath_initialized = 1; + return (0); +} - /* - * Turn privilege back on so that we confirm privilege isn't required - * if we are a group member of the file's group. - */ - set_euid(UID_ROOT); +void +priv_vfs_setgid_fowner(int asroot, int injail, struct test *test) +{ + int error; + + error = chmod(fpath, 0600 | S_ISGID); + if (asroot && injail) + expect("priv_vfs_setgid_fowner(asroot, injail)", error, 0, + 0); + if (asroot && !injail) + expect("priv_vfs_setgid_fowner(asroot, !injail)", error, 0, + 0); + if (!asroot && injail) + expect("priv_vfs_setgid_fowner(!asroot, injail)", error, 0, + 0); + if (!asroot && !injail) + expect("priv_vfs_setgid_fowner(!asroot, !injail)", error, 0, + 0); +} - if (setgroups(2, gidset_with) < 0) { - warn("setgroups(2, {%d, %d})", gidset_with[0], - gidset_with[1]); - goto out; - } +void +priv_vfs_setgid_fother(int asroot, int injail, struct test *test) +{ + int error; + + error = chmod(fpath, 0600 | S_ISGID); + if (asroot && injail) + expect("priv_vfs_setgid_fother(asroot, injail)", error, 0, + 0); + if (asroot && !injail) + expect("priv_vfs_setgid_fother(asroot, !injail)", error, 0, + 0); + if (!asroot && injail) + expect("priv_vfs_setgid_fother(!asroot, injail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_vfs_setgid_fother(!asroot, !injail)", error, -1, + EPERM); +} - if (seteuid(UID_OWNER) < 0) { - warn("seteuid(%d) pass 2", UID_OWNER); - goto out; - } +void +priv_vfs_setgid_cleanup(int asroot, int injail, struct test *test) +{ - /* - * Without privilege, set mode on file (this time with right gid). - */ - if (fchmod(fd, 0600 | S_ISGID) < 0) { - warnx("fchmod(%s, 0600 | S_ISGID) pass 2 as !root", fpath); - sleep(10); - goto out; + if (fpath_initialized) { + (void)unlink(fpath); + fpath_initialized = 0; } - -out: - seteuid(UID_ROOT); - (void)unlink(fpath); } diff --git a/tools/regression/priv/priv_vfs_stickyfile.c b/tools/regression/priv/priv_vfs_stickyfile.c index 11c5d5a..5dcf350 100644 --- a/tools/regression/priv/priv_vfs_stickyfile.c +++ b/tools/regression/priv/priv_vfs_stickyfile.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,8 +31,8 @@ */ /* - * Check that privilege is required to set the sticky bit on a file, but not - * a directory. Try with and without privilege. + * Check that privilege is required to set the sticky bit on a file but not a + * directory. */ #include @@ -42,99 +43,152 @@ #include "main.h" -static void -cleanup(const char *fpath, const char *dpath) +char fpath[1024]; +int fpath_initialized; + +char dpath[1024]; +int dpath_initialized; + +int +priv_vfs_stickyfile_dir_fowner_setup(int asroot, int injail, + struct test *test) { - (void)seteuid(UID_ROOT); - (void)unlink(fpath); - if (dpath != NULL) - (void)rmdir(dpath); + setup_dir("priv_vfs_stickyfile_fowner_setup: dpath", dpath, + UID_OWNER, GID_OWNER, 0700); + dpath_initialized = 1; + return (0); } -void -priv_vfs_stickyfile(void) +int +priv_vfs_stickyfile_dir_fother_setup(int asroot, int injail, + struct test *test) { - char fpath[1024] = "/tmp/stickyfile.XXXXXXXXXXX"; - char dpath[1024] = "/tmp/stickyfile.XXXXXXXXXXX", *dpathp; - int error, fd; - assert_root(); + setup_dir("priv_vfs_stickyfile_fother_setup: dpath", dpath, + UID_OTHER, GID_OTHER, 0700); + dpath_initialized = 1; + return (0); +} - fd = mkstemp(fpath); - if (fd < 0) - err(-1, "mkstemp"); +int +priv_vfs_stickyfile_file_fowner_setup(int asroot, int injail, + struct test *test) +{ - dpathp = mkdtemp(dpath); - if (dpathp == NULL) { - warn("mkdtemp"); - goto out; - } + setup_file("priv_vfs_stickyfile_fowner_setup: fpath", fpath, + UID_OWNER, GID_OWNER, 0600); + fpath_initialized = 1; + return (0); +} - /* - * First, with privilege, set and clear the sticky bit on the file - * and directory. - */ - if (fchmod(fd, 0600 | S_ISTXT) < 0) { - warn("fchmod(%s, 0600 | S_ISTXT) on file as root", fpath); - goto out; - } +int +priv_vfs_stickyfile_file_fother_setup(int asroot, int injail, + struct test *test) +{ - if (chmod(dpathp, 0700 | S_ISTXT) < 0) { - warn("chmod(%s, 0600 | S_ISTXT) on dir as root", dpath); - goto out; - } + setup_file("priv_vfs_stickyfile_fother_setup: fpath", fpath, + UID_OTHER, GID_OTHER, 0600); + fpath_initialized = 1; + return (0); +} - /* - * Reset to remove sticky bit before changing credential. - */ - if (fchmod(fd, 0600) < 0) { - warn("fchmod(%s, 0600) on file as root", fpath); - goto out; - } +void +priv_vfs_stickyfile_dir_fowner(int asroot, int injail, struct test *test) +{ + int error; + + error = chmod(dpath, 0700 | S_ISTXT); + if (asroot && injail) + expect("priv_vfs_stickyfile_dir_fowner(root, jail)", error, + 0, 0); + if (asroot && !injail) + expect("priv_vfs_stickyfile_dir_fowner(root, !jail)", error, + 0, 0); + if (!asroot && injail) + expect("priv_vfs_stickyfile_dir_fowner(!root, jail)", error, + 0, 0); + if (!asroot && !injail) + expect("priv_vfs_stickyfile_dir_fowner(!root, !jail)", error, + 0, 0); +} - if (chmod(dpath, 0700) < 0) { - warn("chmod(%s, 0600) on dir as root", dpath); - goto out; - } +void +priv_vfs_stickyfile_dir_fother(int asroot, int injail, struct test *test) +{ + int error; + + error = chmod(dpath, 0700 | S_ISTXT); + if (asroot && injail) + expect("priv_vfs_stickyfile_dir_fother(root, jail)", error, + 0, 0); + if (asroot && !injail) + expect("priv_vfs_stickyfile_dir_fother(root, !jail)", error, + 0, 0); + if (!asroot && injail) + expect("priv_vfs_stickyfile_dir_fother(!root, jail)", error, + -1, EPERM); + if (!asroot && !injail) + expect("priv_vfs_stickyfile_dir_fother(!root, !jail)", error, + -1, EPERM); +} - /* - * Chown the file and directory to target user -- we're checking for - * the specific right to set the sticky bit, not the general right to - * chmod(). - */ - if (fchown(fd, UID_OTHER, -1) < 0) { - warn("fchown(%s, %d, -1)", fpath, UID_OTHER); - goto out; - } +void +priv_vfs_stickyfile_file_fowner(int asroot, int injail, struct test *test) +{ + int error; + + error = chmod(fpath, 0600 | S_ISTXT); + if (asroot && injail) + expect("priv_vfs_stickyfile_file_fowner(root, jail)", error, + 0, 0); + if (asroot && !injail) + expect("priv_vfs_stickyfile_file_fowner(root, !jail)", error, + 0, 0); + if (!asroot && injail) + expect("priv_vfs_stickyfile_file_fowner(!root, jail)", error, + -1, EFTYPE); + if (!asroot && !injail) + expect("priv_vfs_stickyfile_file_fowner(!root, !jail)", error, + -1, EFTYPE); +} - if (chown(dpath, UID_OTHER, -1) < 0) { - warn("chown(%s, %d, -1)", fpath, UID_OTHER); - goto out; - } +void +priv_vfs_stickyfile_file_fother(int asroot, int injail, struct test *test) +{ + int error; + + error = chmod(fpath, 0600 | S_ISTXT); + if (asroot && injail) + expect("priv_vfs_stickyfile_file_fother(root, jail)", error, + 0, 0); + if (asroot && !injail) + expect("priv_vfs_stickyfile_file_fother(root, !jail)", error, + 0, 0); + if (!asroot && injail) + expect("priv_vfs_stickyfile_file_fother(!root, jail)", error, + -1, EPERM); + if (!asroot && !injail) + expect("priv_vfs_stickyfile_file_fother(!root, !jail)", error, + -1, EPERM); +} - /* - * Change credential and try again. - */ - set_euid(UID_OTHER); +void +priv_vfs_stickyfile_dir_cleanup(int asroot, int injail, struct test *test) +{ - error = fchmod(fd, 0600 | S_ISTXT); - if (error == 0) { - warnx("fchmod(%s, 0600 | S_ISTXT) succeeded on file as " - "!root", fpath); - goto out; - } - if (errno != EFTYPE) { - warn("fchmod(%s, 0600 | S_ISTXT) wrong errno %d as !root", - fpath, errno); - goto out; + if (dpath_initialized) { + (void)rmdir(dpath); + dpath_initialized = 0; } +} + +void +priv_vfs_stickyfile_file_cleanup(int asroot, int injail, struct test *test) +{ - if (chmod(dpathp, 0700 | S_ISTXT) < 0) { - warn("chmod(%s, 0600 | S_ISTXT) on dir as !root", dpath); - goto out; + if (fpath_initialized) { + (void)unlink(fpath); + fpath_initialized = 0; } -out: - setuid(UID_ROOT); - cleanup(fpath, dpathp); } diff --git a/tools/regression/priv/priv_vfs_utimes.c b/tools/regression/priv/priv_vfs_utimes.c new file mode 100644 index 0000000..78fe691 --- /dev/null +++ b/tools/regression/priv/priv_vfs_utimes.c @@ -0,0 +1,224 @@ +/*- + * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson + * All rights reserved. + * + * This software was developed by Robert N. M. Watson for the TrustedBSD + * Project under contract to nCircle Network Security, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, + * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Test NULL and non-NULL tv arguments to utimes() -- if NULL, then it is + * allowed without privilege if the owner or if write access is held. If + * non-NULL, privilege is required even if writable. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "main.h" + +static char fpath[1024]; +static int fpath_initialized; + +int +priv_vfs_utimes_froot_setup(int asroot, int injail, struct test *test) +{ + + setup_file("priv_vfs_utimes_froot_setup: fpath", fpath, + UID_ROOT, GID_WHEEL, 0600); + fpath_initialized = 1; + return (0); +} + +int +priv_vfs_utimes_fowner_setup(int asroot, int injail, struct test *test) +{ + + setup_file("priv_vfs_utimes_fowner_setup: fpath", fpath, + UID_OWNER, GID_OWNER, 0600); + fpath_initialized = 1; + return (0); +} + +int +priv_vfs_utimes_fother_setup(int asroot, int injail, struct test *test) +{ + + /* + * In the 'other' case, we make the file writable by the test user so + * we can evaluate the difference between setting the time to NULL, + * which is possible as a writer, and non-NULL, which requires + * ownership. + */ + setup_file("priv_vfs_utimes_fother_setup: fpath", fpath, + UID_OTHER, GID_OTHER, 0666); + fpath_initialized = 1; + return (0); +} + +void +priv_vfs_utimes_froot(int asroot, int injail, struct test *test) +{ + struct timeval tv[2]; + int error; + + tv[0].tv_sec = 0; + tv[0].tv_usec = 0; + tv[1].tv_sec = 0; + tv[1].tv_usec = 0; + error = utimes(fpath, tv); + if (asroot && injail) + expect("priv_vfs_utimes_froot(root, jail)", error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_utimes_froot(root, !jail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_utimes_froot(!root, jail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_vfs_utimes_froot(!root, !jail)", error, -1, + EPERM); +} + +void +priv_vfs_utimes_froot_null(int asroot, int injail, struct test *test) +{ + int error; + + error = utimes(fpath, NULL); + if (asroot && injail) + expect("priv_vfs_utimes_froot_null(root, jail)", error, 0, + 0); + if (asroot && !injail) + expect("priv_vfs_utimes_froot_null(root, !jail)", error, 0, + 0); + if (!asroot && injail) + expect("priv_vfs_utimes_froot_null(!root, jail)", error, -1, + EACCES); + if (!asroot && !injail) + expect("priv_vfs_utimes_froot_null(!root, !jail)", error, -1, + EACCES); +} + +void +priv_vfs_utimes_fowner(int asroot, int injail, struct test *test) +{ + struct timeval tv[2]; + int error; + + tv[0].tv_sec = 0; + tv[0].tv_usec = 0; + tv[1].tv_sec = 0; + tv[1].tv_usec = 0; + error = utimes(fpath, tv); + if (asroot && injail) + expect("priv_vfs_utimes_fowner(root, jail)", error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_utimes_fowner(root, !jail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_utimes_fowner(!root, jail)", error, 0, 0); + if (!asroot && !injail) + expect("priv_vfs_utimes_fowner(!root, !jail)", error, 0, 0); +} + +void +priv_vfs_utimes_fowner_null(int asroot, int injail, struct test *test) +{ + int error; + + error = utimes(fpath, NULL); + if (asroot && injail) + expect("priv_vfs_utimes_fowner_null(root, jail)", error, 0, + 0); + if (asroot && !injail) + expect("priv_vfs_utimes_fowner_null(root, !jail)", error, 0, + 0); + if (!asroot && injail) + expect("priv_vfs_utimes_fowner_null(!root, jail)", error, 0, + 0); + if (!asroot && !injail) + expect("priv_vfs_utimes_fowner_null(!root, !jail)", error, 0, + 0); +} + +void +priv_vfs_utimes_fother(int asroot, int injail, struct test *test) +{ + struct timeval tv[2]; + int error; + + tv[0].tv_sec = 0; + tv[0].tv_usec = 0; + tv[1].tv_sec = 0; + tv[1].tv_usec = 0; + error = utimes(fpath, tv); + if (asroot && injail) + expect("priv_vfs_utimes_fother(root, jail)", error, 0, 0); + if (asroot && !injail) + expect("priv_vfs_utimes_fother(root, !jail)", error, 0, 0); + if (!asroot && injail) + expect("priv_vfs_utimes_fother(!root, jail)", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_vfs_utimes_fother(!root, !jail)", error, -1, + EPERM); +} + +void +priv_vfs_utimes_fother_null(int asroot, int injail, struct test *test) +{ + int error; + + error = utimes(fpath, NULL); + if (asroot && injail) + expect("priv_vfs_utimes_fother_null(root, jail)", error, 0, + 0); + if (asroot && !injail) + expect("priv_vfs_utimes_fother_null(root, !jail)", error, 0, + 0); + if (!asroot && injail) + expect("priv_vfs_utimes_fother_null(!root, jail)", error, 0, + 0); + if (!asroot && !injail) + expect("priv_vfs_utimes_fother_null(!root, !jail)", error, 0, + 0); +} + +void +priv_vfs_utimes_cleanup(int asroot, int injail, struct test *test) +{ + + if (fpath_initialized) { + (void)unlink(fpath); + fpath_initialized = 0; + } +} diff --git a/tools/regression/priv/priv_vm_madv_protect.c b/tools/regression/priv/priv_vm_madv_protect.c index 737adbf..008e531 100644 --- a/tools/regression/priv/priv_vm_madv_protect.c +++ b/tools/regression/priv/priv_vm_madv_protect.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,8 +31,7 @@ */ /* - * Test that madvise(..., MADV_PROTECT) requires privilege by running it first - * with privilege, then again without. + * Test that madvise(..., MADV_PROTECT) requires privilege. */ #include @@ -43,22 +43,34 @@ #include "main.h" +int +priv_vm_madv_protect_setup(int asroot, int injail, struct test *test) +{ + + return (0); +} + void -priv_vm_madv_protect(void) +priv_vm_madv_protect(int asroot, int injail, struct test *test) { int error; - assert_root(); - error = madvise(NULL, 0, MADV_PROTECT); - if (error) - err(-1, "madvise(..., MADV_PROTECT) as root"); + if (asroot && injail) + expect("priv_vm_madv_protect(asroot, injail)", error, -1, + EPERM); + if (asroot && !injail) + expect("priv_vm_madv_protect(asroot, !injail", error, 0, 0); + if (!asroot && injail) + expect("priv_vm_madv_protect(!asroot, injail", error, -1, + EPERM); + if (!asroot && !injail) + expect("priv_vm_madv_protect(!asroot, !injail", error, -1, + EPERM); +} - set_euid(UID_OTHER); +void +priv_vm_madv_protect_cleanup(int asroot, int injail, struct test *test) +{ - error = madvise(NULL, 0, MADV_PROTECT); - if (error == 0) - errx(-1, "mlock as !root succeeded"); - if (errno != EPERM) - err(-1, "mlock as !root wrong errno %d", errno); } diff --git a/tools/regression/priv/priv_vm_mlock.c b/tools/regression/priv/priv_vm_mlock.c index 3da06d3..5cdbc70 100644 --- a/tools/regression/priv/priv_vm_mlock.c +++ b/tools/regression/priv/priv_vm_mlock.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,8 +31,7 @@ */ /* - * Test that mlock() requires privilege by running it first with privilege, - * then again without. + * Test that mlock() requires privilege. */ #include @@ -43,22 +43,31 @@ #include "main.h" +int +priv_vm_mlock_setup(int asroot, int injail, struct test *test) +{ + + return (0); +} + void -priv_vm_mlock(void) +priv_vm_mlock(int asroot, int injail, struct test *test) { int error; - assert_root(); - error = mlock(&error, getpagesize()); - if (error) - err(-1, "mlock as root"); + if (asroot && injail) + expect("priv_vm_mlock(asroot, injail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_vm_mlock(asroot, !injail", error, 0, 0); + if (!asroot && injail) + expect("priv_vm_mlock(!asroot, injail", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_vm_mlock(!asroot, !injail", error, -1, EPERM); +} - set_euid(UID_OTHER); +void +priv_vm_mlock_cleanup(int asroot, int injail, struct test *test) +{ - error = mlock(&error, getpagesize()); - if (error == 0) - errx(-1, "mlock as !root succeeded"); - if (errno != EPERM) - err(-1, "mlock as !root wrong errno %d", errno); } diff --git a/tools/regression/priv/priv_vm_munlock.c b/tools/regression/priv/priv_vm_munlock.c index 9e8713a..d5a474a 100644 --- a/tools/regression/priv/priv_vm_munlock.c +++ b/tools/regression/priv/priv_vm_munlock.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 nCircle Network Security, Inc. + * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD @@ -30,8 +31,7 @@ */ /* - * Test that munlock() requires privilege by running it first with privilege, - * then again without. + * Test that munlock() requires privilege. */ #include @@ -43,22 +43,32 @@ #include "main.h" +int +priv_vm_munlock_setup(int asroot, int injail, struct test *test) +{ + + return (0); +} + void -priv_vm_munlock(void) +priv_vm_munlock(int asroot, int injail, struct test *test) { int error; - assert_root(); - error = munlock(&error, getpagesize()); - if (error) - err(-1, "munlock as root"); + if (asroot && injail) + expect("priv_vm_munlock(asroot, injail)", error, -1, EPERM); + if (asroot && !injail) + expect("priv_vm_munlock(asroot, !injail", error, 0, 0); + if (!asroot && injail) + expect("priv_vm_munlock(!asroot, injail", error, -1, EPERM); + if (!asroot && !injail) + expect("priv_vm_munlock(!asroot, !injail", error, -1, EPERM); +} - set_euid(UID_OTHER); - error = munlock(&error, getpagesize()); - if (error == 0) - errx(-1, "munlock as !root succeeded"); - if (errno != EPERM) - err(-1, "munlock as !root wrong errno %d", errno); +void +priv_vm_munlock_cleanup(int asroot, int injail, struct test *test) +{ + } diff --git a/tools/regression/priv/test_utimes.c b/tools/regression/priv/test_utimes.c deleted file mode 100644 index 51cef52..0000000 --- a/tools/regression/priv/test_utimes.c +++ /dev/null @@ -1,153 +0,0 @@ -/*- - * Copyright (c) 2006 nCircle Network Security, Inc. - * All rights reserved. - * - * This software was developed by Robert N. M. Watson for the TrustedBSD - * Project under contract to nCircle Network Security, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, - * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * If times is NULL, ... The caller must be the owner of the file, have - * permission to write the file, or be the super-user. - * - * If times is non-NULL, ... The caller must be the owner of the file or be - * the super-user. - * - * To test these, create a temporary file owned by uid_owner; then run a - * series of tests as root, owner, and other, along with various modes, to - * see what is permitted, and if not, what error is returned. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "main.h" - -static int -try_utimes(const char *path, mode_t mode, uid_t uid, - struct timeval *timestamp, int expected) -{ - int error; - - if (chmod(path, mode) < 0) { - warn("try_utimes(%s, %d, %d, 0x%08x): chmod", path, mode, uid, - (u_int)timestamp); - (void)unlink(path); - exit(-1); - } - - if (seteuid(uid) < 0) { - warn("try_utimes(%s, %d, %d, 0x%08x): seteuid(%d)", path, - mode, uid, (u_int)timestamp, uid); - (void)unlink(path); - exit(-1); - } - - error = utimes(path, timestamp); - - if (seteuid(UID_ROOT) < 0) { - warn("try_utimes(%s, %d, %d, 0x%08x): seteuid(UID_ROOT)", - path, mode, uid, (u_int)timestamp); - (void)unlink(path); - exit(-1); - } - - if (expected == 0) { - if (error != 0) { - (void)unlink(path); - errx(-1, "try_utimes(%s, 0%o, %d, 0x%08x) failed %d", - path, mode, uid, (u_int)timestamp, errno); - } - return (0); - } - - if (expected == errno) - return (0); - - (void)unlink(path); - errx(-1, "try_utimes(%s, 0%o, %d, 0x%08x) wrong err %d", path, mode, - uid, (u_int)timestamp, errno); -} - -void -test_utimes(void) -{ - char path[128] = "/tmp/utimes.XXXXXXXXX"; - struct timeval timestamp[2]; - int fd; - - if (getuid() != 0) - errx(-1, "must be run as root"); - - fd = mkstemp(path); - if (fd == -1) - err(-1, "mkstemp"); - - if (chown(path, UID_OWNER, -1) < 0) { - warn("chown(%s, %d)", path, UID_OWNER); - (void)unlink(path); - return; - } - - bzero(timestamp, sizeof(timestamp)); - - try_utimes(path, 0444, UID_ROOT, NULL, 0); - try_utimes(path, 0444, UID_OWNER, NULL, 0); - /* Denied by permissions. */ - try_utimes(path, 0444, UID_OTHER, NULL, EACCES); - - try_utimes(path, 0444, UID_ROOT, timestamp, 0); - try_utimes(path, 0444, UID_OWNER, timestamp, 0); - try_utimes(path, 0444, UID_OTHER, timestamp, EPERM); - - try_utimes(path, 0644, UID_ROOT, NULL, 0); - try_utimes(path, 0644, UID_OWNER, NULL, 0); - /* Denied by permissions. */ - try_utimes(path, 0644, UID_OTHER, NULL, EACCES); - - try_utimes(path, 0644, UID_ROOT, timestamp, 0); - try_utimes(path, 0644, UID_OWNER, timestamp, 0); - /* Denied as not owner. */ - try_utimes(path, 0644, UID_OTHER, timestamp, EPERM); - - try_utimes(path, 0666, UID_ROOT, NULL, 0); - try_utimes(path, 0666, UID_OWNER, NULL, 0); - try_utimes(path, 0666, UID_OTHER, NULL, 0); - - try_utimes(path, 0666, UID_ROOT, timestamp, 0); - try_utimes(path, 0666, UID_OWNER, timestamp, 0); - /* Denied as not owner. */ - try_utimes(path, 0666, UID_OTHER, timestamp, EPERM); - - (void)unlink(path); -} -- cgit v1.1