summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2006-09-13 09:05:39 +0000
committerrwatson <rwatson@FreeBSD.org>2006-09-13 09:05:39 +0000
commitbd76450bdb09c2e5764e93c84a74137048511894 (patch)
treeec2dcf761c2bc37f81afe69bfa26e908994add75
parent166e57c29a09569bc76efcc5752635fc36c9c1da (diff)
downloadFreeBSD-src-bd76450bdb09c2e5764e93c84a74137048511894.zip
FreeBSD-src-bd76450bdb09c2e5764e93c84a74137048511894.tar.gz
dd a series of regression tests to validate that privilege requirements are
implemented properly for a number of kernel subsystems. In general, they try to exercise the privilege first as the root user, then as a test user, in order to determine when privilege is being checked. Currently, these tests do not compare inside/outside jail, and probably should be enhanced to do that. Sponsored by: nCircle Network Security, Inc. Obtained from: TrustedBSD Project
-rw-r--r--tools/regression/priv/Makefile40
-rw-r--r--tools/regression/priv/main.c184
-rw-r--r--tools/regression/priv/main.h90
-rw-r--r--tools/regression/priv/priv_acct.c178
-rw-r--r--tools/regression/priv/priv_adjtime.c75
-rw-r--r--tools/regression/priv/priv_clock_settime.c76
-rw-r--r--tools/regression/priv/priv_io.c135
-rw-r--r--tools/regression/priv/priv_kenv_set.c68
-rw-r--r--tools/regression/priv/priv_kenv_unset.c77
-rw-r--r--tools/regression/priv/priv_proc_setlogin.c73
-rw-r--r--tools/regression/priv/priv_proc_setrlimit.c137
-rw-r--r--tools/regression/priv/priv_sched_rtprio.c234
-rw-r--r--tools/regression/priv/priv_sched_setpriority.c163
-rw-r--r--tools/regression/priv/priv_settimeofday.c76
-rw-r--r--tools/regression/priv/priv_sysctl_write.c89
-rw-r--r--tools/regression/priv/priv_vfs_admin.c328
-rw-r--r--tools/regression/priv/priv_vfs_chown.c170
-rw-r--r--tools/regression/priv/priv_vfs_chroot.c63
-rw-r--r--tools/regression/priv/priv_vfs_clearsugid.c215
-rw-r--r--tools/regression/priv/priv_vfs_extattr_system.c96
-rw-r--r--tools/regression/priv/priv_vfs_fhopen.c92
-rw-r--r--tools/regression/priv/priv_vfs_fhstat.c89
-rw-r--r--tools/regression/priv/priv_vfs_fhstatfs.c89
-rw-r--r--tools/regression/priv/priv_vfs_generation.c113
-rw-r--r--tools/regression/priv/priv_vfs_getfh.c78
-rw-r--r--tools/regression/priv/priv_vfs_read_write.c370
-rw-r--r--tools/regression/priv/priv_vfs_setgid.c143
-rw-r--r--tools/regression/priv/priv_vfs_stickyfile.c140
-rw-r--r--tools/regression/priv/priv_vm_madv_protect.c64
-rw-r--r--tools/regression/priv/priv_vm_mlock.c64
-rw-r--r--tools/regression/priv/priv_vm_munlock.c64
-rw-r--r--tools/regression/priv/test_utimes.c153
32 files changed, 4026 insertions, 0 deletions
diff --git a/tools/regression/priv/Makefile b/tools/regression/priv/Makefile
new file mode 100644
index 0000000..7a8d7a0
--- /dev/null
+++ b/tools/regression/priv/Makefile
@@ -0,0 +1,40 @@
+#
+# $FreeBSD$
+#
+
+PROG= main
+SRCS= main.c \
+ priv_acct.c \
+ priv_adjtime.c \
+ priv_clock_settime.c \
+ priv_io.c \
+ priv_kenv_set.c \
+ priv_kenv_unset.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_chown.c \
+ priv_vfs_chroot.c \
+ priv_vfs_clearsugid.c \
+ priv_vfs_extattr_system.c \
+ priv_vfs_fhopen.c \
+ priv_vfs_fhstat.c \
+ priv_vfs_fhstatfs.c \
+ priv_vfs_generation.c \
+ priv_vfs_getfh.c \
+ priv_vfs_read_write.c \
+ priv_vfs_setgid.c \
+ priv_vfs_stickyfile.c \
+ priv_vm_mlock.c \
+ priv_vm_munlock.c \
+ priv_vm_madv_protect.c \
+ \
+ test_utimes.c
+NO_MAN=
+WARNS= 3
+
+.include <bsd.prog.mk>
diff --git a/tools/regression/priv/main.c b/tools/regression/priv/main.c
new file mode 100644
index 0000000..90622ad
--- /dev/null
+++ b/tools/regression/priv/main.c
@@ -0,0 +1,184 @@
+/*-
+ * 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$
+ */
+
+/*
+ * 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/stat.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "main.h"
+
+/*
+ * Common routines used across many tests.
+ */
+void
+assert_root(void)
+{
+
+ if (getuid() != UID_ROOT || geteuid() != UID_ROOT)
+ err(-1, "must be run as root");
+}
+
+void
+setup_file(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");
+
+ if (fchown(fd, uid, gid) < 0)
+ err(-1, "fchown(%s, %d, %d)", fpathp, uid, gid);
+
+ if (fchmod(fd, mode) < 0)
+ err(-1, "chmod(%s, 0%o)", fpathp, mode);
+
+ close(fd);
+}
+
+/*
+ * When downgrading privileges, set the gid before the uid; when upgrading,
+ * set uid before gid.
+ */
+void
+set_creds(uid_t uid, gid_t gid)
+{
+
+ if (setegid(gid) < 0)
+ err(-1, "setegid(%d)", gid);
+ if (seteuid(uid) < 0)
+ err(-1, "seteuid(%d)", uid);
+}
+
+void
+set_euid(uid_t uid)
+{
+
+ if (seteuid(uid) < 0)
+ err(-1, "seteuid(%d)", uid);
+}
+
+void
+restore_creds(void)
+{
+
+ if (seteuid(UID_ROOT) < 0)
+ err(-1, "seteuid(%d)", UID_ROOT);
+ if (setegid(GID_WHEEL) < 0)
+ err(-1, "setegid(%d)", GID_WHEEL);
+}
+
+/*
+ * 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.
+ */
+static void
+run(const char *funcname, void (*func)(void))
+{
+ pid_t childpid, pid;
+
+ printf("running %s\n", funcname);
+ fflush(stdout);
+ fflush(stderr);
+ childpid = fork();
+ if (childpid == -1)
+ err(-1, "test %s unable to fork", funcname);
+ if (childpid == 0) {
+ setprogname(funcname);
+ func();
+ fflush(stdout);
+ fflush(stderr);
+ exit(0);
+ } else {
+ while (1) {
+ pid = waitpid(childpid, NULL, 0);
+ if (pid == -1)
+ warn("waitpid %s", funcname);
+ if (pid == childpid)
+ break;
+ }
+ }
+ fflush(stdout);
+ fflush(stderr);
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ 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);
+
+ return (0);
+}
diff --git a/tools/regression/priv/main.h b/tools/regression/priv/main.h
new file mode 100644
index 0000000..6c5616b
--- /dev/null
+++ b/tools/regression/priv/main.h
@@ -0,0 +1,90 @@
+/*-
+ * 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$
+ */
+
+#define UID_ROOT 0
+#define UID_OWNER 100
+#define UID_OTHER 200
+#define UID_THIRD 300
+
+#define GID_WHEEL 0
+#define GID_OWNER 100
+#define GID_OTHER 200
+
+#define KENV_VAR_NAME "test"
+#define KENV_VAR_VALUE "test"
+
+/*
+ * 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);
+
+/*
+ * Tests for specific privileges.
+ */
+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);
+
+/*
+ * Tests for more complex access control logic involving more than one
+ * privilege, or privilege combined with DAC.
+ */
+void test_utimes(void);
diff --git a/tools/regression/priv/priv_acct.c b/tools/regression/priv/priv_acct.c
new file mode 100644
index 0000000..bc4a41e7
--- /dev/null
+++ b/tools/regression/priv/priv_acct.c
@@ -0,0 +1,178 @@
+/*-
+ * 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$
+ */
+
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "main.h"
+
+#define SYSCTL_NAME "kern.acct_configured"
+#define PATH_TEMPLATE "/tmp/acct.XXXXXXXXXXX"
+
+void
+priv_acct(void)
+{
+ char fpath1[1024] = PATH_TEMPLATE;
+ char fpath2[1024] = PATH_TEMPLATE;
+ int error, fd, i;
+ size_t len;
+
+ 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",
+ 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);
+ }
+
+ /*
+ * 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;
+ }
+
+ if (chmod(fpath2, 0666) < 0) {
+ warn("chmod(%s, 0600)", fpath2);
+ goto out;
+ }
+
+ /*
+ * Test that privileged can move through entire life cycle.
+ */
+ if (acct(fpath1) < 0) {
+ warn("acct(NULL -> %s) as root", fpath1);
+ goto out;
+ }
+
+ if (acct(fpath2) < 0) {
+ warn("acct(%s -> %s) as root", fpath1, fpath2);
+ goto out;
+ }
+
+ if (acct(NULL) < 0) {
+ warn("acct(%s -> NULL) as root", fpath1);
+ goto out;
+ }
+
+ /*
+ * 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;
+ }
+
+ set_euid(UID_ROOT);
+ if (acct(fpath1) < 0) {
+ err(-1, "acct(NULL -> %s) setup for !root", fpath1);
+ goto out;
+ }
+
+ 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;
+ }
+
+ set_euid(UID_ROOT);
+ if (acct(fpath2) < 0) {
+ err(-1, "acct(%s -> %s) setup for !root", fpath1, fpath2);
+ goto out;
+ }
+
+ 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);
+}
diff --git a/tools/regression/priv/priv_adjtime.c b/tools/regression/priv/priv_adjtime.c
new file mode 100644
index 0000000..791de97
--- /dev/null
+++ b/tools/regression/priv/priv_adjtime.c
@@ -0,0 +1,75 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Confirm that privilege is required to invoke adjtime(); first query, then
+ * try setting first with, and then without privilege.
+ */
+
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_adjtime(void)
+{
+ struct timeval tv;
+ int error;
+
+ assert_root();
+
+ /*
+ * Query time adjustment.
+ */
+ if (adjtime(NULL, &tv) < 0)
+ err(-1, "adjtime");
+
+ /*
+ * Set with privilege.
+ */
+ if (adjtime(&tv, NULL) < 0)
+ err(-1, "adjtime as root");
+
+ /*
+ * Set without privilege.
+ */
+ set_euid(UID_OTHER);
+
+ 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_clock_settime.c b/tools/regression/priv/priv_clock_settime.c
new file mode 100644
index 0000000..e3d1089
--- /dev/null
+++ b/tools/regression/priv/priv_clock_settime.c
@@ -0,0 +1,76 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Confirm that privilege is required to invoke clock_settime(). So as not
+ * to mess up the clock too much, first query the time, then immediately set
+ * it. Test only CLOCK_REALTIME.
+ */
+
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_clock_settime(void)
+{
+ struct timespec ts;
+ int error;
+
+ assert_root();
+
+ /*
+ * Query time.
+ */
+ if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
+ err(-1, "clock_gettime");
+
+ /*
+ * Set with privilege.
+ */
+ if (clock_settime(CLOCK_REALTIME, &ts) < 0)
+ err(-1, "clock_settime as root");
+
+ /*
+ * Set without privilege.
+ */
+ set_euid(UID_OTHER);
+
+ 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_io.c b/tools/regression/priv/priv_io.c
new file mode 100644
index 0000000..1af1847
--- /dev/null
+++ b/tools/regression/priv/priv_io.c
@@ -0,0 +1,135 @@
+/*-
+ * 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$
+ */
+
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "main.h"
+
+#define NEW_PERMS 0660
+#define DEV_IO "/dev/io"
+#define EXPECTED_PERMS 0600
+
+static mode_t saved_perms;
+
+static void
+save_perms(void)
+{
+ struct stat sb;
+
+ if (stat(DEV_IO, &sb) < 0)
+ err(-1, "save_perms: stat(%s)", DEV_IO);
+
+ 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);
+}
+
+static void
+try_open(const char *test_case, uid_t uid, int expected)
+{
+ int 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;
+ }
+ 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)
+{
+
+ 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();
+}
diff --git a/tools/regression/priv/priv_kenv_set.c b/tools/regression/priv/priv_kenv_set.c
new file mode 100644
index 0000000..96e785d
--- /dev/null
+++ b/tools/regression/priv/priv_kenv_set.c
@@ -0,0 +1,68 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Test that setting a kernel environment variable requires privilege, by
+ * first trying it with privilege, then without.
+ */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <kenv.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_kenv_set(void)
+{
+ 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");
+
+ set_euid(UID_OTHER);
+
+ 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);
+}
diff --git a/tools/regression/priv/priv_kenv_unset.c b/tools/regression/priv/priv_kenv_unset.c
new file mode 100644
index 0000000..2bb800d
--- /dev/null
+++ b/tools/regression/priv/priv_kenv_unset.c
@@ -0,0 +1,77 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Test that setting a kernel environment variable, then trying to unset it
+ * without and with privilege.
+ */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <kenv.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_kenv_unset(void)
+{
+ 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_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");
+
+ set_euid(UID_OTHER);
+
+ 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);
+}
diff --git a/tools/regression/priv/priv_proc_setlogin.c b/tools/regression/priv/priv_proc_setlogin.c
new file mode 100644
index 0000000..6f5e756
--- /dev/null
+++ b/tools/regression/priv/priv_proc_setlogin.c
@@ -0,0 +1,73 @@
+/*-
+ * 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$
+ */
+
+/*
+ * 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.
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_proc_setlogin(void)
+{
+ char *loginname;
+ int error;
+
+ assert_root();
+
+ loginname = getlogin();
+ if (loginname == NULL)
+ err(-1, "getlogin");
+
+ /*
+ * First, with privilege.
+ */
+ error = setlogin(loginname);
+ if (error)
+ err(-1, "setlogin(%s) as root", loginname);
+
+ /*
+ * Then again, without privilege.
+ */
+ set_euid(UID_OTHER);
+
+ 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);
+}
diff --git a/tools/regression/priv/priv_proc_setrlimit.c b/tools/regression/priv/priv_proc_setrlimit.c
new file mode 100644
index 0000000..adf471b
--- /dev/null
+++ b/tools/regression/priv/priv_proc_setrlimit.c
@@ -0,0 +1,137 @@
+/*-
+ * 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$
+ */
+
+/*
+ * 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.
+ *
+ * - To raise the maximum.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_proc_setrlimit(void)
+{
+ struct rlimit rl, rl_lower, rl_raise_max, rl_raise_cur;
+ int error;
+
+ assert_root();
+
+ /*
+ * 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)");
+
+ /*
+ * What to lower to before trying to raise.
+ */
+ rl_lower = rl;
+ rl_lower.rlim_cur -= 10;
+ rl_lower.rlim_max = rl_lower.rlim_cur;
+
+ /*
+ * Raise the maximum.
+ */
+ rl_raise_max = rl;
+ rl_raise_max.rlim_max += 10;
+
+ /*
+ * Raise the current above the maximum.
+ */
+ rl_raise_cur = rl;
+ rl_raise_cur.rlim_cur += 10;
+
+ /*
+ * Test raising the maximum with privilege.
+ */
+ if (setrlimit(RLIMIT_DATA, &rl_lower) < 0)
+ err(-1, "setrlimit(RLIMIT_DATA, lower) as root");
+
+ if (setrlimit(RLIMIT_DATA, &rl_raise_max) < 0)
+ err(-1, "setrlimit(RLIMIT_DATA, raise_max) as root");
+
+ /*
+ * Test raising the current above the maximum with privilege.
+ */
+ if (setrlimit(RLIMIT_DATA, &rl_lower) < 0)
+ err(-1, "setrlimit(RLIMIT_DATA, lower) as root");
+
+ if (setrlimit(RLIMIT_DATA, &rl_raise_cur) < 0)
+ err(-1, "setrlimit(RLIMIT_DATA, raise_cur) as root");
+
+ /*
+ * 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);
+
+ /*
+ * 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);
+}
diff --git a/tools/regression/priv/priv_sched_rtprio.c b/tools/regression/priv/priv_sched_rtprio.c
new file mode 100644
index 0000000..72d1756
--- /dev/null
+++ b/tools/regression/priv/priv_sched_rtprio.c
@@ -0,0 +1,234 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Test privilege associated with real time process settings. There are
+ * three relevant notions of privilege:
+ *
+ * - Privilege to set the real-time priority of the current process.
+ * - Privilege to set the real-time priority of another process.
+ * - Privilege to set the idle priority of another process.
+ * - No privilege to set the idle priority of the current process.
+ *
+ * This requires a test process and a target (dummy) process running with
+ * various uids. This test is based on the code in the setpriority() test.
+ */
+
+#include <sys/types.h>
+#include <sys/rtprio.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "main.h"
+
+static void
+dummy(void)
+{
+
+ while (1)
+ sleep(1);
+}
+
+static void
+collect(pid_t test_pid, pid_t dummy_pid)
+{
+ pid_t pid;
+
+ /*
+ * First, collect the main test process. When it has exited, then
+ * kill off the dummy process.
+ */
+ 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;
+ }
+ }
+
+ 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;
+ }
+}
+
+static void
+test(pid_t dummy_pid)
+{
+ 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.prio = 0;
+ if (rtprio(RTP_SET, 0, &rtp) < 0)
+ err(-1, "rtprio(RTP_SET, 0, {REALTIME, 0}) as root");
+
+ 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");
+
+ 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");
+
+ 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);
+
+ 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);
+
+ 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);
+
+ /*
+ * Then test again as a different credential.
+ */
+ if (setresuid(UID_OTHER, UID_OTHER, UID_OTHER) < 0)
+ err(-1, "setresuid(%d)", UID_OTHER);
+
+ rtp.type = RTP_PRIO_REALTIME;
+ 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);
+
+ rtp.type = RTP_PRIO_IDLE;
+ 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);
+
+ 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");
+
+ 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);
+
+ 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);
+}
+
+void
+priv_sched_rtprio(void)
+{
+ pid_t dummy_pid, test_pid;
+
+ assert_root();
+
+ /*
+ * 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. */
+
+ test_pid = fork();
+ if (test_pid < 0) {
+ warn("fork - test");
+ collect(-1, dummy_pid);
+ return;
+ }
+ 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
new file mode 100644
index 0000000..4d56813
--- /dev/null
+++ b/tools/regression/priv/priv_sched_setpriority.c
@@ -0,0 +1,163 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Test that privilege is required to lower nice value; first test with, then
+ * without. There are two failure modes associated with privilege: the right
+ * to renice a process with a different uid, and the right to renice to a
+ * lower priority. Because both the real and effective uid are part of the
+ * permissions test, we have to create two children processes with different
+ * uids.
+ */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "main.h"
+
+static void
+dummy(void)
+{
+
+ while (1)
+ sleep(1);
+}
+
+static void
+collect(pid_t test_pid, pid_t dummy_pid)
+{
+ pid_t pid;
+
+ /*
+ * First, collect the main test process. When it has exited, then
+ * kill off the dummy process.
+ */
+ 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;
+ }
+ }
+
+ 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;
+ }
+}
+
+static void
+test(pid_t dummy_pid)
+{
+ int error;
+
+ /*
+ * Tests first as root.
+ */
+ if (setpriority(PRIO_PROCESS, 0, -1) < 0)
+ err(-1, "setpriority(PRIO_PROCESS, 0, -1) as root");
+
+ if (setpriority(PRIO_PROCESS, dummy_pid, -1) < 0)
+ err(-1, "setpriority(PRIO_PROCESS, %d, -1) as root",
+ dummy_pid);
+
+ /*
+ * 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);
+}
+
+void
+priv_sched_setpriority(void)
+{
+ pid_t dummy_pid, test_pid;
+
+ assert_root();
+
+ /*
+ * 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. */
+
+ test_pid = fork();
+ if (test_pid < 0) {
+ warn("fork - test");
+ collect(-1, dummy_pid);
+ return;
+ }
+ 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
new file mode 100644
index 0000000..d18582f
--- /dev/null
+++ b/tools/regression/priv/priv_settimeofday.c
@@ -0,0 +1,76 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Confirm that privilege is required to invoke settimeofday(). So as not
+ * to mess up the clock too much, first query the time, then immediately set
+ * it.
+ */
+
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_settimeofday(void)
+{
+ struct timeval tv;
+ int error;
+
+ assert_root();
+
+ /*
+ * Query time.
+ */
+ if (gettimeofday(&tv, NULL) < 0)
+ err(-1, "gettimeofday");
+
+ /*
+ * Set with privilege.
+ */
+ if (settimeofday(&tv, NULL) < 0)
+ err(-1, "settimeofday as root");
+
+ /*
+ * Set without privilege.
+ */
+ set_euid(UID_OTHER);
+
+ 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
new file mode 100644
index 0000000..becff06
--- /dev/null
+++ b/tools/regression/priv/priv_sysctl_write.c
@@ -0,0 +1,89 @@
+/*-
+ * 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$
+ */
+
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "main.h"
+
+#define KERN_HOSTNAME_STRING "kern.hostname"
+
+void
+priv_sysctl_write(void)
+{
+ 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",
+ KERN_HOSTNAME_STRING);
+
+ /*
+ * Now without privilege.
+ */
+ set_euid(UID_OTHER);
+
+ 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
new file mode 100644
index 0000000..f06e9b2
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_admin.c
@@ -0,0 +1,328 @@
+/*-
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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_chown.c b/tools/regression/priv/priv_vfs_chown.c
new file mode 100644
index 0000000..8d72ac2
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_chown.c
@@ -0,0 +1,170 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Confirm that privilege is required in the cases using chown():
+ *
+ * - If the process euid does not match the file uid.
+ *
+ * - If the target uid is different than the current uid.
+ *
+ * - If the target gid changes and we the process is not a member of the new
+ * group.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "main.h"
+
+const gid_t gidset[] = {GID_WHEEL, GID_OWNER};
+
+void
+priv_vfs_chown(void)
+{
+ char fpath[1024];
+ int error;
+
+ assert_root();
+
+ /*
+ * 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);
+
+ /*
+ * 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.
+ */
+ 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);
+
+ /*
+ * 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);
+
+ /*
+ * 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);
+
+ /*
+ * 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 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.
+ */
+ setup_file(fpath, UID_OWNER, GID_OWNER, 0600);
+ set_euid(UID_OWNER);
+ 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;
+ }
+ 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
new file mode 100644
index 0000000..06c36d4
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_chroot.c
@@ -0,0 +1,63 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Test that chroot() requires privilege; try with, and without. Do a no-op
+ * chroot() to "/".
+ *
+ * XXXRW: Would also be good to check fchroot() permission, but that is not
+ * exposed via the BSD API.
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_vfs_chroot(void)
+{
+ int error;
+
+ assert_root();
+
+ if (chroot("/") < 0)
+ err(-1, "chroot(\"/\") as root");
+
+ set_euid(UID_OTHER);
+
+ 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
new file mode 100644
index 0000000..a8ddcd5
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_clearsugid.c
@@ -0,0 +1,215 @@
+/*-
+ * 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$
+ */
+
+/*
+ * There are three cases in which the file system will clear the setuid or
+ * setgid bits on a file when running as !root:
+ *
+ * - When the file is chown()'d and either of the uid or the gid is changed.
+ *
+ * - The file is written to succeesfully.
+ *
+ * - 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.
+ */
+
+#include <sys/types.h>
+#include <sys/extattr.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "main.h"
+
+static const gid_t gidset[] = {GID_WHEEL, GID_OWNER, GID_OTHER};
+
+/*
+ * Confirm that the setuid bit is set on a file. Don't return on failure.
+ */
+static void
+confirm_setuid(char *fpathp, char *test_case)
+{
+ 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) not setuid", test_case, fpathp);
+ (void)seteuid(UID_ROOT);
+ (void)unlink(fpathp);
+ exit(-1);
+ }
+}
+
+/*
+ * 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)
+{
+ 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);
+ }
+}
+
+#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)
+{
+ 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);
+ 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);
+
+out:
+ (void)seteuid(UID_ROOT);
+ (void)unlink(fpath);
+}
diff --git a/tools/regression/priv/priv_vfs_extattr_system.c b/tools/regression/priv/priv_vfs_extattr_system.c
new file mode 100644
index 0000000..d67c550
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_extattr_system.c
@@ -0,0 +1,96 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Test that privilege is required to write to the system extended attribute
+ * namespace.
+ */
+
+#include <sys/types.h>
+#include <sys/extattr.h>
+
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "main.h"
+
+#define EA_NAMESPACE EXTATTR_NAMESPACE_SYSTEM
+#define EA_NAME "test"
+#define EA_DATA "test"
+#define EA_SIZE strlen(EA_DATA)
+
+void
+priv_vfs_extattr_system(void)
+{
+ char fpath[1024];
+ int error;
+
+ assert_root();
+
+ /*
+ * 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);
+
+ /*
+ * 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;
+ }
+
+ set_euid(UID_OTHER);
+
+ /*
+ * 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;
+ }
+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
new file mode 100644
index 0000000..cb4006d
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_fhopen.c
@@ -0,0 +1,92 @@
+/*-
+ * 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$
+ */
+
+/*
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_vfs_fhopen(void)
+{
+ char fpath[1024];
+ fhandle_t fh;
+ int fd;
+
+ assert_root();
+
+ setup_file(fpath, UID_ROOT, GID_WHEEL, 0644);
+
+ if (getfh(fpath, &fh) < 0) {
+ warn("getfh(%s)", fpath);
+ goto out;
+ }
+
+ /*
+ * 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);
+
+ fd = fhopen(&fh, O_RDONLY);
+ if (fd >= 0) {
+ warnx("fhopen(%s) succeeded as !root", fpath);
+ close(fd);
+ goto out;
+ }
+ if (errno != EPERM) {
+ warn("fhopen(%s) wrong errno %d as !root", fpath, errno);
+ goto out;
+ }
+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
new file mode 100644
index 0000000..c8e58e8
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_fhstat.c
@@ -0,0 +1,89 @@
+/*-
+ * 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$
+ */
+
+/*
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_vfs_fhstat(void)
+{
+ char fpath[1024];
+ struct stat sb;
+ fhandle_t fh;
+ int error;
+
+ assert_root();
+
+ setup_file(fpath, UID_ROOT, GID_WHEEL, 0644);
+
+ if (getfh(fpath, &fh) < 0) {
+ warn("getfh(%s)", fpath);
+ goto out;
+ }
+
+ /*
+ * First, try with privilege.
+ */
+ if (fhstat(&fh, &sb) < 0) {
+ warn("fhstat(%s) as root", fpath);
+ goto out;
+ }
+
+ /*
+ * 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;
+ }
+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
new file mode 100644
index 0000000..4709fe2
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_fhstatfs.c
@@ -0,0 +1,89 @@
+/*-
+ * 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$
+ */
+
+/*
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_vfs_fhstatfs(void)
+{
+ char fpath[1024];
+ struct statfs sf;
+ fhandle_t fh;
+ int error;
+
+ assert_root();
+
+ setup_file(fpath, UID_ROOT, GID_WHEEL, 0644);
+
+ 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;
+ }
+
+ /*
+ * Now, without privilege.
+ */
+ set_euid(UID_OTHER);
+
+ 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;
+ }
+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
new file mode 100644
index 0000000..2ccca79
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_generation.c
@@ -0,0 +1,113 @@
+/*-
+ * 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$
+ */
+
+/*
+ * 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.
+ */
+
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "main.h"
+
+/*
+ * Can't use setup_file() since the resulting file needs to have specific
+ * properties.
+ */
+void
+priv_vfs_generation(void)
+{
+ char fpath[1024] = "/tmp/priv.XXXXXXXXXX";
+ struct stat sb;
+ int fd, i;
+
+ assert_root();
+
+ /*
+ * 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...
+ */
+ 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;
+ }
+ 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);
+
+ /*
+ * 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;
+ }
+
+ set_euid(UID_OTHER);
+
+ if (stat(fpath, &sb) < 0) {
+ warn("stat(%s) as !root", fpath);
+ goto out;
+ }
+
+ if (sb.st_gen != 0)
+ warn("stat(%s) returned generation as !root", fpath);
+
+out:
+ (void)seteuid(UID_ROOT);
+ (void)unlink(fpath);
+}
diff --git a/tools/regression/priv/priv_vfs_getfh.c b/tools/regression/priv/priv_vfs_getfh.c
new file mode 100644
index 0000000..ff5d6fe
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_getfh.c
@@ -0,0 +1,78 @@
+/*-
+ * 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 getfh() requires privilege; run it with, and without,
+ * privilege.
+ */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_vfs_getfh(void)
+{
+ 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 (errno != EPERM) {
+ warn("getfh(%s) wrong errno %d as !root", fpath, errno);
+ goto out;
+ }
+
+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
new file mode 100644
index 0000000..c7f479d
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_read_write.c
@@ -0,0 +1,370 @@
+/*-
+ * 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$
+ */
+
+/*
+ * This is a joint test of both the read and write privileges with respect to
+ * discretionary file system access control (permissions). Only permissions,
+ * not ACL semantics, and only privilege-related checks are performed.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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;
+};
+
+/*
+ * 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 void
+test_perm(struct test_arguments ta, mode_t file_mode, int expected)
+{
+ 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);
+ } 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);
+ }
+ }
+
+ restore_creds();
+ (void)unlink(fpath);
+}
+
+static const gid_t gidset[] = { GID_WHEEL };
+
+static void
+preamble(void)
+{
+
+ if (getuid() != UID_ROOT)
+ errx(-1, "must be run as root");
+ if (setgroups(1, gidset) < 0)
+ err(-1, "setgroups(1, {%d})", GID_WHEEL);
+}
+
+void
+priv_vfs_read(void)
+{
+ 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);
+
+ /*
+ * 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;
+
+ 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);
+}
+
+void
+priv_vfs_write(void)
+{
+ 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);
+
+ /*
+ * 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, 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);
+
+ /*
+ * 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, 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);
+
+ /*
+ * 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;
+
+ 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);
+}
diff --git a/tools/regression/priv/priv_vfs_setgid.c b/tools/regression/priv/priv_vfs_setgid.c
new file mode 100644
index 0000000..b763ef6
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_setgid.c
@@ -0,0 +1,143 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Test that privilege is required to set the sgid bit on a file with a group
+ * that isn't in the process credential. The file uid owner is set to the
+ * uid being tested with, as we are not interested in testing privileges
+ * associated with file ownership.
+ */
+
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "main.h"
+
+static const gid_t gidset_without[] = {GID_WHEEL};
+static const gid_t gidset_with[] = {GID_WHEEL, GID_OWNER};
+
+void
+priv_vfs_setgid(void)
+{
+ 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;
+ }
+
+ /*
+ * Drop privilege.
+ */
+ set_euid(UID_OWNER);
+
+ /*
+ * 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;
+ }
+
+ /*
+ * 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);
+
+ if (setgroups(2, gidset_with) < 0) {
+ warn("setgroups(2, {%d, %d})", gidset_with[0],
+ gidset_with[1]);
+ goto out;
+ }
+
+ if (seteuid(UID_OWNER) < 0) {
+ warn("seteuid(%d) pass 2", UID_OWNER);
+ goto out;
+ }
+
+ /*
+ * 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;
+ }
+
+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
new file mode 100644
index 0000000..11c5d5a
--- /dev/null
+++ b/tools/regression/priv/priv_vfs_stickyfile.c
@@ -0,0 +1,140 @@
+/*-
+ * 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 to set the sticky bit on a file, but not
+ * a directory. Try with and without privilege.
+ */
+
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+static void
+cleanup(const char *fpath, const char *dpath)
+{
+
+ (void)seteuid(UID_ROOT);
+ (void)unlink(fpath);
+ if (dpath != NULL)
+ (void)rmdir(dpath);
+}
+
+void
+priv_vfs_stickyfile(void)
+{
+ char fpath[1024] = "/tmp/stickyfile.XXXXXXXXXXX";
+ char dpath[1024] = "/tmp/stickyfile.XXXXXXXXXXX", *dpathp;
+ int error, fd;
+
+ assert_root();
+
+ fd = mkstemp(fpath);
+ if (fd < 0)
+ err(-1, "mkstemp");
+
+ dpathp = mkdtemp(dpath);
+ if (dpathp == NULL) {
+ warn("mkdtemp");
+ goto out;
+ }
+
+ /*
+ * 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;
+ }
+
+ if (chmod(dpathp, 0700 | S_ISTXT) < 0) {
+ warn("chmod(%s, 0600 | S_ISTXT) on dir as root", dpath);
+ goto out;
+ }
+
+ /*
+ * Reset to remove sticky bit before changing credential.
+ */
+ if (fchmod(fd, 0600) < 0) {
+ warn("fchmod(%s, 0600) on file as root", fpath);
+ goto out;
+ }
+
+ if (chmod(dpath, 0700) < 0) {
+ warn("chmod(%s, 0600) on dir as root", dpath);
+ goto out;
+ }
+
+ /*
+ * 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;
+ }
+
+ if (chown(dpath, UID_OTHER, -1) < 0) {
+ warn("chown(%s, %d, -1)", fpath, UID_OTHER);
+ goto out;
+ }
+
+ /*
+ * Change credential and try again.
+ */
+ set_euid(UID_OTHER);
+
+ 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 (chmod(dpathp, 0700 | S_ISTXT) < 0) {
+ warn("chmod(%s, 0600 | S_ISTXT) on dir as !root", dpath);
+ goto out;
+ }
+out:
+ setuid(UID_ROOT);
+ cleanup(fpath, dpathp);
+}
diff --git a/tools/regression/priv/priv_vm_madv_protect.c b/tools/regression/priv/priv_vm_madv_protect.c
new file mode 100644
index 0000000..737adbf
--- /dev/null
+++ b/tools/regression/priv/priv_vm_madv_protect.c
@@ -0,0 +1,64 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Test that madvise(..., MADV_PROTECT) requires privilege by running it first
+ * with privilege, then again without.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_vm_madv_protect(void)
+{
+ int error;
+
+ assert_root();
+
+ error = madvise(NULL, 0, MADV_PROTECT);
+ if (error)
+ err(-1, "madvise(..., MADV_PROTECT) as root");
+
+ set_euid(UID_OTHER);
+
+ 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
new file mode 100644
index 0000000..3da06d3
--- /dev/null
+++ b/tools/regression/priv/priv_vm_mlock.c
@@ -0,0 +1,64 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Test that mlock() requires privilege by running it first with privilege,
+ * then again without.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_vm_mlock(void)
+{
+ int error;
+
+ assert_root();
+
+ error = mlock(&error, getpagesize());
+ if (error)
+ err(-1, "mlock as root");
+
+ set_euid(UID_OTHER);
+
+ 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
new file mode 100644
index 0000000..9e8713a
--- /dev/null
+++ b/tools/regression/priv/priv_vm_munlock.c
@@ -0,0 +1,64 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Test that munlock() requires privilege by running it first with privilege,
+ * then again without.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+void
+priv_vm_munlock(void)
+{
+ int error;
+
+ assert_root();
+
+ error = munlock(&error, getpagesize());
+ if (error)
+ err(-1, "munlock as root");
+
+ 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);
+}
diff --git a/tools/regression/priv/test_utimes.c b/tools/regression/priv/test_utimes.c
new file mode 100644
index 0000000..51cef52
--- /dev/null
+++ b/tools/regression/priv/test_utimes.c
@@ -0,0 +1,153 @@
+/*-
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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);
+}
OpenPOWER on IntegriCloud