|
|
c2dfb7 |
From b39697a80ad388e2063c54e56333882f4307c1a1 Mon Sep 17 00:00:00 2001
|
|
|
c2dfb7 |
From: Jan Synacek <jsynacek@redhat.com>
|
|
|
c2dfb7 |
Date: Tue, 12 Nov 2019 13:27:49 +0100
|
|
|
c2dfb7 |
Subject: [PATCH] test: add test case for restrict_suid_sgid()
|
|
|
c2dfb7 |
|
|
|
c2dfb7 |
(cherry picked from commit 167fc10cb352b04d442c9010dab4f8dc24219749)
|
|
|
c2dfb7 |
Related: #1687512
|
|
|
c2dfb7 |
---
|
|
|
c2dfb7 |
src/test/test-seccomp.c | 226 ++++++++++++++++++++++++++++++++++++++++
|
|
|
c2dfb7 |
1 file changed, 226 insertions(+)
|
|
|
c2dfb7 |
|
|
|
c2dfb7 |
diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c
|
|
|
c2dfb7 |
index d177515ac7..4021a06e0e 100644
|
|
|
c2dfb7 |
--- a/src/test/test-seccomp.c
|
|
|
c2dfb7 |
+++ b/src/test/test-seccomp.c
|
|
|
c2dfb7 |
@@ -17,9 +17,11 @@
|
|
|
c2dfb7 |
#include "nsflags.h"
|
|
|
c2dfb7 |
#include "process-util.h"
|
|
|
c2dfb7 |
#include "raw-clone.h"
|
|
|
c2dfb7 |
+#include "rm-rf.h"
|
|
|
c2dfb7 |
#include "seccomp-util.h"
|
|
|
c2dfb7 |
#include "set.h"
|
|
|
c2dfb7 |
#include "string-util.h"
|
|
|
c2dfb7 |
+#include "umask-util.h"
|
|
|
c2dfb7 |
#include "util.h"
|
|
|
c2dfb7 |
#include "virt.h"
|
|
|
c2dfb7 |
|
|
|
c2dfb7 |
@@ -666,6 +668,229 @@ static void test_filter_sets_ordered(void) {
|
|
|
c2dfb7 |
}
|
|
|
c2dfb7 |
}
|
|
|
c2dfb7 |
|
|
|
c2dfb7 |
+static int mkostemp_safe(char *pattern) {
|
|
|
c2dfb7 |
+ _unused_ _cleanup_umask_ mode_t u = umask(0077);
|
|
|
c2dfb7 |
+ int fd;
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert(pattern);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ fd = mkostemp(pattern, O_CLOEXEC);
|
|
|
c2dfb7 |
+ if (fd < 0)
|
|
|
c2dfb7 |
+ return -errno;
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ return fd;
|
|
|
c2dfb7 |
+}
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+static int real_open(const char *path, int flags, mode_t mode) {
|
|
|
c2dfb7 |
+ /* glibc internally calls openat() when open() is requested. Let's hence define our own wrapper for
|
|
|
c2dfb7 |
+ * testing purposes that calls the real syscall, on architectures where SYS_open is defined. On
|
|
|
c2dfb7 |
+ * other architectures, let's just fall back to the glibc call. */
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+#ifdef SYS_open
|
|
|
c2dfb7 |
+ return (int) syscall(SYS_open, path, flags, mode);
|
|
|
c2dfb7 |
+#else
|
|
|
c2dfb7 |
+ return open(path, flags, mode);
|
|
|
c2dfb7 |
+#endif
|
|
|
c2dfb7 |
+}
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+static void test_restrict_suid_sgid(void) {
|
|
|
c2dfb7 |
+ pid_t pid;
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ log_info("/* %s */", __func__);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ if (!is_seccomp_available()) {
|
|
|
c2dfb7 |
+ log_notice("Seccomp not available, skipping %s", __func__);
|
|
|
c2dfb7 |
+ return;
|
|
|
c2dfb7 |
+ }
|
|
|
c2dfb7 |
+ if (geteuid() != 0) {
|
|
|
c2dfb7 |
+ log_notice("Not root, skipping %s", __func__);
|
|
|
c2dfb7 |
+ return;
|
|
|
c2dfb7 |
+ }
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ pid = fork();
|
|
|
c2dfb7 |
+ assert_se(pid >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ if (pid == 0) {
|
|
|
c2dfb7 |
+ char path[] = "/tmp/suidsgidXXXXXX", dir[] = "/tmp/suidsgiddirXXXXXX";
|
|
|
c2dfb7 |
+ int fd = -1, k = -1;
|
|
|
c2dfb7 |
+ const char *z;
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ fd = mkostemp_safe(path);
|
|
|
c2dfb7 |
+ assert_se(fd >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(mkdtemp(dir));
|
|
|
c2dfb7 |
+ z = strjoina(dir, "/test");
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(chmod(path, 0755 | S_ISUID) >= 0);
|
|
|
c2dfb7 |
+ assert_se(chmod(path, 0755 | S_ISGID) >= 0);
|
|
|
c2dfb7 |
+ assert_se(chmod(path, 0755 | S_ISGID | S_ISUID) >= 0);
|
|
|
c2dfb7 |
+ assert_se(chmod(path, 0755) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(fchmod(fd, 0755 | S_ISUID) >= 0);
|
|
|
c2dfb7 |
+ assert_se(fchmod(fd, 0755 | S_ISGID) >= 0);
|
|
|
c2dfb7 |
+ assert_se(fchmod(fd, 0755 | S_ISGID | S_ISUID) >= 0);
|
|
|
c2dfb7 |
+ assert_se(fchmod(fd, 0755) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISUID, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ k = creat(z, 0644 | S_ISUID);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ k = creat(z, 0644 | S_ISGID);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ k = creat(z, 0644 | S_ISUID | S_ISGID);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ k = creat(z, 0644);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(mkdir(z, 0755 | S_ISUID) >= 0);
|
|
|
c2dfb7 |
+ assert_se(rmdir(z) >= 0);
|
|
|
c2dfb7 |
+ assert_se(mkdir(z, 0755 | S_ISGID) >= 0);
|
|
|
c2dfb7 |
+ assert_se(rmdir(z) >= 0);
|
|
|
c2dfb7 |
+ assert_se(mkdir(z, 0755 | S_ISUID | S_ISGID) >= 0);
|
|
|
c2dfb7 |
+ assert_se(rmdir(z) >= 0);
|
|
|
c2dfb7 |
+ assert_se(mkdir(z, 0755) >= 0);
|
|
|
c2dfb7 |
+ assert_se(rmdir(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID) >= 0);
|
|
|
c2dfb7 |
+ assert_se(rmdir(z) >= 0);
|
|
|
c2dfb7 |
+ assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISGID) >= 0);
|
|
|
c2dfb7 |
+ assert_se(rmdir(z) >= 0);
|
|
|
c2dfb7 |
+ assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID | S_ISGID) >= 0);
|
|
|
c2dfb7 |
+ assert_se(rmdir(z) >= 0);
|
|
|
c2dfb7 |
+ assert_se(mkdirat(AT_FDCWD, z, 0755) >= 0);
|
|
|
c2dfb7 |
+ assert_se(rmdir(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(mknod(z, S_IFREG | 0755 | S_ISUID, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+ assert_se(mknod(z, S_IFREG | 0755 | S_ISGID, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+ assert_se(mknod(z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+ assert_se(mknod(z, S_IFREG | 0755, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISGID, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(seccomp_restrict_suid_sgid() >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(chmod(path, 0775 | S_ISUID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(chmod(path, 0775 | S_ISGID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(chmod(path, 0775 | S_ISGID | S_ISUID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(chmod(path, 0775) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(fchmod(fd, 0775 | S_ISUID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(fchmod(fd, 0775 | S_ISGID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(fchmod(fd, 0775 | S_ISGID | S_ISUID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(fchmod(fd, 0775) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISUID, 0) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID, 0) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(creat(z, 0644 | S_ISUID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(creat(z, 0644 | S_ISGID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(creat(z, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ k = creat(z, 0644);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
|
|
|
c2dfb7 |
+ k = safe_close(k);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(mkdir(z, 0755 | S_ISUID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(mkdir(z, 0755 | S_ISGID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(mkdir(z, 0755 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(mkdir(z, 0755) >= 0);
|
|
|
c2dfb7 |
+ assert_se(rmdir(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISGID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(mkdirat(AT_FDCWD, z, 0755) >= 0);
|
|
|
c2dfb7 |
+ assert_se(rmdir(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(mknod(z, S_IFREG | 0755 | S_ISUID, 0) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(mknod(z, S_IFREG | 0755 | S_ISGID, 0) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(mknod(z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(mknod(z, S_IFREG | 0755, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID, 0) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISGID, 0) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) < 0 && errno == EPERM);
|
|
|
c2dfb7 |
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755, 0) >= 0);
|
|
|
c2dfb7 |
+ assert_se(unlink(z) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(unlink(path) >= 0);
|
|
|
c2dfb7 |
+ assert_se(rm_rf(dir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ _exit(EXIT_SUCCESS);
|
|
|
c2dfb7 |
+ }
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
+ assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
|
|
|
c2dfb7 |
+}
|
|
|
c2dfb7 |
+
|
|
|
c2dfb7 |
int main(int argc, char *argv[]) {
|
|
|
c2dfb7 |
|
|
|
c2dfb7 |
log_set_max_level(LOG_DEBUG);
|
|
|
c2dfb7 |
@@ -684,6 +909,7 @@ int main(int argc, char *argv[]) {
|
|
|
c2dfb7 |
test_load_syscall_filter_set_raw();
|
|
|
c2dfb7 |
test_lock_personality();
|
|
|
c2dfb7 |
test_filter_sets_ordered();
|
|
|
c2dfb7 |
+ test_restrict_suid_sgid();
|
|
|
c2dfb7 |
|
|
|
c2dfb7 |
return 0;
|
|
|
c2dfb7 |
}
|