summaryrefslogtreecommitdiffstats
path: root/tools/regression/priv/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/regression/priv/main.c')
-rw-r--r--tools/regression/priv/main.c455
1 files changed, 384 insertions, 71 deletions
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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/jail.h>
#include <sys/stat.h>
#include <sys/wait.h>
+#include <netinet/in.h>
+
#include <err.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -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);
}
OpenPOWER on IntegriCloud