Skip to content

Commit

Permalink
selftests/seccomp: Handle namespace failures gracefully
Browse files Browse the repository at this point in the history
When running without USERNS or PIDNS the seccomp test would hang since
it was waiting forever for the child to trigger the user notification
since it seems the glibc() abort handler makes a call to getpid(),
which would trap again. This changes the getpid filter to getppid, and
makes sure ASSERTs execute to stop from spawning the listener.

Reported-by: Shuah Khan <shuah@kernel.org>
Fixes: 6a21cc5 ("seccomp: add a return code to trap to userspace")
Cc: stable@vger.kernel.org # > 5.0
Signed-off-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Tycho Andersen <tycho@tycho.ws>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
  • Loading branch information
Kees Cook authored and Shuah Khan committed Apr 16, 2019
1 parent e14d314 commit 9dd3fcb
Showing 1 changed file with 23 additions and 20 deletions.
43 changes: 23 additions & 20 deletions tools/testing/selftests/seccomp/seccomp_bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -3079,9 +3079,9 @@ TEST(user_notification_basic)

/* Check that we get -ENOSYS with no listener attached */
if (pid == 0) {
if (user_trap_syscall(__NR_getpid, 0) < 0)
if (user_trap_syscall(__NR_getppid, 0) < 0)
exit(1);
ret = syscall(__NR_getpid);
ret = syscall(__NR_getppid);
exit(ret >= 0 || errno != ENOSYS);
}

Expand All @@ -3096,12 +3096,12 @@ TEST(user_notification_basic)
EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);

/* Check that the basic notification machinery works */
listener = user_trap_syscall(__NR_getpid,
listener = user_trap_syscall(__NR_getppid,
SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);

/* Installing a second listener in the chain should EBUSY */
EXPECT_EQ(user_trap_syscall(__NR_getpid,
EXPECT_EQ(user_trap_syscall(__NR_getppid,
SECCOMP_FILTER_FLAG_NEW_LISTENER),
-1);
EXPECT_EQ(errno, EBUSY);
Expand All @@ -3110,7 +3110,7 @@ TEST(user_notification_basic)
ASSERT_GE(pid, 0);

if (pid == 0) {
ret = syscall(__NR_getpid);
ret = syscall(__NR_getppid);
exit(ret != USER_NOTIF_MAGIC);
}

Expand All @@ -3128,7 +3128,7 @@ TEST(user_notification_basic)
EXPECT_GT(poll(&pollfd, 1, -1), 0);
EXPECT_EQ(pollfd.revents, POLLOUT);

EXPECT_EQ(req.data.nr, __NR_getpid);
EXPECT_EQ(req.data.nr, __NR_getppid);

resp.id = req.id;
resp.error = 0;
Expand Down Expand Up @@ -3160,7 +3160,7 @@ TEST(user_notification_kill_in_middle)
TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
}

listener = user_trap_syscall(__NR_getpid,
listener = user_trap_syscall(__NR_getppid,
SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);

Expand All @@ -3172,7 +3172,7 @@ TEST(user_notification_kill_in_middle)
ASSERT_GE(pid, 0);

if (pid == 0) {
ret = syscall(__NR_getpid);
ret = syscall(__NR_getppid);
exit(ret != USER_NOTIF_MAGIC);
}

Expand Down Expand Up @@ -3282,7 +3282,7 @@ TEST(user_notification_closed_listener)
TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
}

listener = user_trap_syscall(__NR_getpid,
listener = user_trap_syscall(__NR_getppid,
SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);

Expand All @@ -3293,7 +3293,7 @@ TEST(user_notification_closed_listener)
ASSERT_GE(pid, 0);
if (pid == 0) {
close(listener);
ret = syscall(__NR_getpid);
ret = syscall(__NR_getppid);
exit(ret != -1 && errno != ENOSYS);
}

Expand All @@ -3316,14 +3316,15 @@ TEST(user_notification_child_pid_ns)

ASSERT_EQ(unshare(CLONE_NEWUSER | CLONE_NEWPID), 0);

listener = user_trap_syscall(__NR_getpid, SECCOMP_FILTER_FLAG_NEW_LISTENER);
listener = user_trap_syscall(__NR_getppid,
SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);

pid = fork();
ASSERT_GE(pid, 0);

if (pid == 0)
exit(syscall(__NR_getpid) != USER_NOTIF_MAGIC);
exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);

EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
EXPECT_EQ(req.pid, pid);
Expand Down Expand Up @@ -3355,7 +3356,8 @@ TEST(user_notification_sibling_pid_ns)
TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
}

listener = user_trap_syscall(__NR_getpid, SECCOMP_FILTER_FLAG_NEW_LISTENER);
listener = user_trap_syscall(__NR_getppid,
SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);

pid = fork();
Expand All @@ -3368,7 +3370,7 @@ TEST(user_notification_sibling_pid_ns)
ASSERT_GE(pid2, 0);

if (pid2 == 0)
exit(syscall(__NR_getpid) != USER_NOTIF_MAGIC);
exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);

EXPECT_EQ(waitpid(pid2, &status, 0), pid2);
EXPECT_EQ(true, WIFEXITED(status));
Expand All @@ -3377,19 +3379,19 @@ TEST(user_notification_sibling_pid_ns)
}

/* Create the sibling ns, and sibling in it. */
EXPECT_EQ(unshare(CLONE_NEWPID), 0);
EXPECT_EQ(errno, 0);
ASSERT_EQ(unshare(CLONE_NEWPID), 0);
ASSERT_EQ(errno, 0);

pid2 = fork();
EXPECT_GE(pid2, 0);
ASSERT_GE(pid2, 0);

if (pid2 == 0) {
ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
/*
* The pid should be 0, i.e. the task is in some namespace that
* we can't "see".
*/
ASSERT_EQ(req.pid, 0);
EXPECT_EQ(req.pid, 0);

resp.id = req.id;
resp.error = 0;
Expand Down Expand Up @@ -3419,14 +3421,15 @@ TEST(user_notification_fault_recv)

ASSERT_EQ(unshare(CLONE_NEWUSER), 0);

listener = user_trap_syscall(__NR_getpid, SECCOMP_FILTER_FLAG_NEW_LISTENER);
listener = user_trap_syscall(__NR_getppid,
SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);

pid = fork();
ASSERT_GE(pid, 0);

if (pid == 0)
exit(syscall(__NR_getpid) != USER_NOTIF_MAGIC);
exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);

/* Do a bad recv() */
EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, NULL), -1);
Expand Down

0 comments on commit 9dd3fcb

Please sign in to comment.