summaryrefslogtreecommitdiffstats
path: root/tools/regression/priv/priv_vfs_clearsugid.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/regression/priv/priv_vfs_clearsugid.c')
-rw-r--r--tools/regression/priv/priv_vfs_clearsugid.c209
1 files changed, 73 insertions, 136 deletions
diff --git a/tools/regression/priv/priv_vfs_clearsugid.c b/tools/regression/priv/priv_vfs_clearsugid.c
index a8ddcd5..b62a928 100644
--- a/tools/regression/priv/priv_vfs_clearsugid.c
+++ b/tools/regression/priv/priv_vfs_clearsugid.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2006 nCircle Network Security, Inc.
+ * Copyright (c) 2007 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by Robert N. M. Watson for the TrustedBSD
@@ -31,16 +32,21 @@
/*
* There are three cases in which the file system will clear the setuid or
- * setgid bits on a file when running as !root:
+ * setgid bits on a file when running unprivileged:
*
* - When the file is chown()'d and either of the uid or the gid is changed.
+ * (currently, only changing the file gid applies, as privilege is required
+ * to change the uid).
*
- * - The file is written to succeesfully.
+ * - The file is written to successfully.
*
* - An extended attribute of the file is written to successfully.
*
- * Test each case first as root (that flags aren't cleared), and then as
- * !root, to check they are cleared.
+ * In each case, check that the flags are cleared if unprivileged, and that
+ * they aren't cleared if privileged.
+ *
+ * We can't use expect() as we're looking for side-effects rather than
+ * success/failure of the system call.
*/
#include <sys/types.h>
@@ -55,161 +61,92 @@
#include "main.h"
-static const gid_t gidset[] = {GID_WHEEL, GID_OWNER, GID_OTHER};
+static char fpath[1024];
+static int fpath_initialized;
/*
- * Confirm that the setuid bit is set on a file. Don't return on failure.
+ * If running as root, check that SUID is still set; otherwise, check that it
+ * is not.
*/
static void
-confirm_setuid(char *fpathp, char *test_case)
+confirm_sugid(char *test_case, int asroot, int injail)
{
struct stat sb;
- if (stat(fpathp, &sb) < 0) {
- warn("%s stat(%s)", test_case, fpathp);
- (void)seteuid(UID_ROOT);
- (void)unlink(fpathp);
- exit(-1);
+ if (stat(fpath, &sb) < 0) {
+ warn("%s stat(%s)", test_case, fpath);
+ return;
}
- if (!(sb.st_mode & S_ISUID)) {
- warnx("case %s stat(%s) not setuid", test_case, fpathp);
- (void)seteuid(UID_ROOT);
- (void)unlink(fpathp);
- exit(-1);
+ if (asroot) {
+ if (!(sb.st_mode & S_ISUID))
+ warnx("%s(root, %s): !SUID", test_case, injail ?
+ "jail" : "!jail");
+ } else {
+ if (sb.st_mode & S_ISUID)
+ warnx("%s(!root, %s): SUID", test_case, injail ?
+ "jail" : "!jail");
}
}
-/*
- * Confirm that the setuid bit is not set on a file. Don't return on failure.
- */
-static void
-confirm_notsetuid(char *fpathp, char *test_case)
+int
+priv_vfs_clearsugid_setup(int asroot, int injail, struct test *test)
{
- struct stat sb;
- if (stat(fpathp, &sb) < 0) {
- warn("%s stat(%s)", test_case, fpathp);
- (void)seteuid(UID_ROOT);
- (void)unlink(fpathp);
- exit(-1);
- }
- if (sb.st_mode & S_ISUID) {
- warnx("case %s stat(%s) is setuid", test_case, fpathp);
- (void)seteuid(UID_ROOT);
- (void)unlink(fpathp);
- exit(-1);
- }
+ setup_file("priv_vfs_clearsugid_setup: fpath", fpath, UID_OWNER,
+ GID_OTHER, 0600 | S_ISUID);
+ fpath_initialized = 1;
+ return (0);
+}
+
+void
+priv_vfs_clearsugid_chgrp(int asroot, int injail, struct test *test)
+{
+
+ if (chown(fpath, -1, asroot ? GID_WHEEL : GID_OWNER) < 0)
+ err(-1, "priv_vfs_clearsugid_chgrp(%s, %s): chrgrp",
+ asroot ? "root" : "!root", injail ? "jail" : "!jail");
+ confirm_sugid("priv_vfs_clearsugid_chgrp", asroot, injail);
}
#define EA_NAMESPACE EXTATTR_NAMESPACE_USER
#define EA_NAME "clearsugid"
#define EA_DATA "test"
#define EA_SIZE (strlen(EA_DATA))
+
void
-priv_vfs_clearsugid(void)
+priv_vfs_clearsugid_extattr(int asroot, int injail, struct test *test)
{
- char ch, fpath[1024];
- int fd;
- assert_root();
-
- /*
- * Before starting on work, set up group IDs so that the process can
- * change the group ID of the file without privilege, in order to see
- * the effects. That way privilege is only required to maintain the
- * setuid bit. For the chown() test, we change only the group id, as
- * that can be done with or without privilege.
- */
- if (setgroups(3, gidset) < 0)
- err(-1, "setgroups(2, {%d, %d})", GID_WHEEL, GID_OWNER);
-
- /*
- * chown() with privilege.
- */
- setup_file(fpath, UID_ROOT, GID_WHEEL, 0600 | S_ISUID);
- if (chown(fpath, -1, GID_OTHER) < 0)
- warn("chown(%s, -1, %d) as root", fpath, GID_OTHER);
- confirm_setuid(fpath, "chown as root");
- (void)unlink(fpath);
-
- /*
- * write() with privilege.
- */
- setup_file(fpath, UID_ROOT, GID_WHEEL, 0600 | S_ISUID);
- fd = open(fpath, O_RDWR);
- if (fd < 0) {
- warn("open(%s) as root", fpath);
- goto out;
- }
- ch = 0;
- if (write(fd, &ch, sizeof(ch)) < 0) {
- warn("write(%s) as root", fpath);
- goto out;
- }
- close(fd);
- confirm_setuid(fpath, "write as root");
- (void)unlink(fpath);
-
- /*
- * extwrite() with privilege.
- */
- setup_file(fpath, UID_ROOT, GID_WHEEL, 0600 | S_ISUID);
if (extattr_set_file(fpath, EA_NAMESPACE, EA_NAME, EA_DATA, EA_SIZE)
- < 0) {
- warn("extattr_set_file(%s, user, %s, %s, %d) as root",
- fpath, EA_NAME, EA_DATA, EA_SIZE);
- goto out;
- }
- confirm_setuid(fpath, "extwrite as root");
- (void)unlink(fpath);
-
- /*
- * chown() without privilege.
- */
- setup_file(fpath, UID_OWNER, GID_OWNER, 0600 | S_ISUID);
- set_euid(UID_OWNER);
- if (chown(fpath, -1, GID_OTHER) < 0)
- warn("chown(%s, -1, %d) as !root", fpath, GID_OTHER);
- set_euid(UID_ROOT);
- confirm_notsetuid(fpath, "chown as !root");
- (void)unlink(fpath);
-
- /*
- * write() without privilege.
- */
- setup_file(fpath, UID_OWNER, GID_OWNER, 0600 | S_ISUID);
- set_euid(UID_OWNER);
+ < 0)
+ err(-1,
+ "priv_vfs_clearsugid_extattr(%s, %s): extattr_set_file",
+ asroot ? "root" : "!root", injail ? "jail" : "!jail");
+ confirm_sugid("priv_vfs_clearsugid_extattr", asroot, injail);
+}
+
+void
+priv_vfs_clearsugid_write(int asroot, int injail, struct test *test)
+{
+ int fd;
+
fd = open(fpath, O_RDWR);
- if (fd < 0) {
- warn("open(%s) as !root", fpath);
- goto out;
- }
- ch = 0;
- if (write(fd, &ch, sizeof(ch)) < 0) {
- warn("write(%s) as !root", fpath);
- goto out;
- }
- close(fd);
- set_euid(UID_ROOT);
- confirm_notsetuid(fpath, "write as !root");
- (void)unlink(fpath);
-
- /*
- * extwrite() without privilege.
- */
- setup_file(fpath, UID_OWNER, GID_OWNER, 0600 | S_ISUID);
- set_euid(UID_OWNER);
- if (extattr_set_file(fpath, EA_NAMESPACE, EA_NAME, EA_DATA, EA_SIZE)
- < 0) {
- warn("extattr_set_file(%s, user, %s, %s, %d) as !root",
- fpath, EA_NAME, EA_DATA, EA_SIZE);
- goto out;
- }
- set_euid(UID_ROOT);
- confirm_notsetuid(fpath, "extwrite as !root");
- (void)unlink(fpath);
+ if (fd < 0)
+ err(-1, "priv_vfs_clearsugid_write(%s, %s): open",
+ asroot ? "root" : "!root", injail ? "jail" : "!jail");
+ if (write(fd, EA_DATA, EA_SIZE) < 0)
+ err(-1, "priv_vfs_clearsugid_write(%s, %s): write",
+ asroot ? "root" : "!root", injail ? "jail" : "!jail");
+ (void)close(fd);
+ confirm_sugid("priv_vfs_clearsugid_write", asroot, injail);
+}
-out:
- (void)seteuid(UID_ROOT);
- (void)unlink(fpath);
+void
+priv_vfs_clearsugid_cleanup(int asroot, int injail, struct test *test)
+{
+
+ if (fpath_initialized) {
+ (void)unlink(fpath);
+ fpath_initialized = 0;
+ }
}
OpenPOWER on IntegriCloud