selftests/seccomp: Test PTRACE_O_SUSPEND_SECCOMP without CAP_SYS_ADMIN
authorJann Horn <jannh@google.com>
Sat, 19 Mar 2022 01:08:38 +0000 (02:08 +0100)
committerKees Cook <keescook@chromium.org>
Fri, 29 Apr 2022 18:28:42 +0000 (11:28 -0700)
Add a test to check that PTRACE_O_SUSPEND_SECCOMP can't be set without
CAP_SYS_ADMIN through PTRACE_SEIZE or PTRACE_SETOPTIONS.

Signed-off-by: Jann Horn <jannh@google.com>
Co-developed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Kees Cook <keescook@chromium.org>
tools/testing/selftests/seccomp/Makefile
tools/testing/selftests/seccomp/seccomp_bpf.c

index 585f7a0..f017c38 100644 (file)
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 CFLAGS += -Wl,-no-as-needed -Wall -isystem ../../../../usr/include/
 LDFLAGS += -lpthread
+LDLIBS += -lcap
 
 TEST_GEN_PROGS := seccomp_bpf seccomp_benchmark
 include ../lib.mk
index 313bb0c..4da9051 100644 (file)
@@ -46,6 +46,7 @@
 #include <sys/ioctl.h>
 #include <linux/kcmp.h>
 #include <sys/resource.h>
+#include <sys/capability.h>
 
 #include <unistd.h>
 #include <sys/syscall.h>
@@ -4231,6 +4232,68 @@ TEST(user_notification_addfd_rlimit)
        close(memfd);
 }
 
+/* Make sure PTRACE_O_SUSPEND_SECCOMP requires CAP_SYS_ADMIN. */
+FIXTURE(O_SUSPEND_SECCOMP) {
+       pid_t pid;
+};
+
+FIXTURE_SETUP(O_SUSPEND_SECCOMP)
+{
+       ERRNO_FILTER(block_read, E2BIG);
+       cap_value_t cap_list[] = { CAP_SYS_ADMIN };
+       cap_t caps;
+
+       self->pid = 0;
+
+       /* make sure we don't have CAP_SYS_ADMIN */
+       caps = cap_get_proc();
+       ASSERT_NE(NULL, caps);
+       ASSERT_EQ(0, cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_CLEAR));
+       ASSERT_EQ(0, cap_set_proc(caps));
+       cap_free(caps);
+
+       ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
+       ASSERT_EQ(0, prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_block_read));
+
+       self->pid = fork();
+       ASSERT_GE(self->pid, 0);
+
+       if (self->pid == 0) {
+               while (1)
+                       pause();
+               _exit(127);
+       }
+}
+
+FIXTURE_TEARDOWN(O_SUSPEND_SECCOMP)
+{
+       if (self->pid)
+               kill(self->pid, SIGKILL);
+}
+
+TEST_F(O_SUSPEND_SECCOMP, setoptions)
+{
+       int wstatus;
+
+       ASSERT_EQ(0, ptrace(PTRACE_ATTACH, self->pid, NULL, 0));
+       ASSERT_EQ(self->pid, wait(&wstatus));
+       ASSERT_EQ(-1, ptrace(PTRACE_SETOPTIONS, self->pid, NULL, PTRACE_O_SUSPEND_SECCOMP));
+       if (errno == EINVAL)
+               SKIP(return, "Kernel does not support PTRACE_O_SUSPEND_SECCOMP (missing CONFIG_CHECKPOINT_RESTORE?)");
+       ASSERT_EQ(EPERM, errno);
+}
+
+TEST_F(O_SUSPEND_SECCOMP, seize)
+{
+       int ret;
+
+       ret = ptrace(PTRACE_SEIZE, self->pid, NULL, PTRACE_O_SUSPEND_SECCOMP);
+       ASSERT_EQ(-1, ret);
+       if (errno == EINVAL)
+               SKIP(return, "Kernel does not support PTRACE_O_SUSPEND_SECCOMP (missing CONFIG_CHECKPOINT_RESTORE?)");
+       ASSERT_EQ(EPERM, errno);
+}
+
 /*
  * TODO:
  * - expand NNP testing