Skip to content

Commit 0eebfed

Browse files
Christian Braunerkees
authored andcommitted
seccomp: test SECCOMP_USER_NOTIF_FLAG_CONTINUE
Test whether a syscall can be performed after having been intercepted by the seccomp notifier. The test uses dup() and kcmp() since it allows us to nicely test whether the dup() syscall actually succeeded by comparing whether the fds refer to the same underlying struct file. Signed-off-by: Christian Brauner <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Will Drewry <[email protected]> Cc: Shuah Khan <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Daniel Borkmann <[email protected]> Cc: Martin KaFai Lau <[email protected]> Cc: Song Liu <[email protected]> Cc: Yonghong Song <[email protected]> Cc: Tycho Andersen <[email protected]> CC: Tyler Hicks <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Kees Cook <[email protected]>
1 parent fb3c538 commit 0eebfed

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

tools/testing/selftests/seccomp/seccomp_bpf.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include <sys/times.h>
4545
#include <sys/socket.h>
4646
#include <sys/ioctl.h>
47+
#include <linux/kcmp.h>
4748

4849
#include <unistd.h>
4950
#include <sys/syscall.h>
@@ -167,6 +168,10 @@ struct seccomp_metadata {
167168

168169
#define SECCOMP_RET_USER_NOTIF 0x7fc00000U
169170

171+
#ifndef SECCOMP_USER_NOTIF_FLAG_CONTINUE
172+
#define SECCOMP_USER_NOTIF_FLAG_CONTINUE 0x00000001
173+
#endif
174+
170175
#define SECCOMP_IOC_MAGIC '!'
171176
#define SECCOMP_IO(nr) _IO(SECCOMP_IOC_MAGIC, nr)
172177
#define SECCOMP_IOR(nr, type) _IOR(SECCOMP_IOC_MAGIC, nr, type)
@@ -3486,6 +3491,108 @@ TEST(seccomp_get_notif_sizes)
34863491
EXPECT_EQ(sizes.seccomp_notif_resp, sizeof(struct seccomp_notif_resp));
34873492
}
34883493

3494+
static int filecmp(pid_t pid1, pid_t pid2, int fd1, int fd2)
3495+
{
3496+
#ifdef __NR_kcmp
3497+
return syscall(__NR_kcmp, pid1, pid2, KCMP_FILE, fd1, fd2);
3498+
#else
3499+
errno = ENOSYS;
3500+
return -1;
3501+
#endif
3502+
}
3503+
3504+
TEST(user_notification_continue)
3505+
{
3506+
pid_t pid;
3507+
long ret;
3508+
int status, listener;
3509+
struct seccomp_notif req = {};
3510+
struct seccomp_notif_resp resp = {};
3511+
struct pollfd pollfd;
3512+
3513+
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
3514+
ASSERT_EQ(0, ret) {
3515+
TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
3516+
}
3517+
3518+
listener = user_trap_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
3519+
ASSERT_GE(listener, 0);
3520+
3521+
pid = fork();
3522+
ASSERT_GE(pid, 0);
3523+
3524+
if (pid == 0) {
3525+
int dup_fd, pipe_fds[2];
3526+
pid_t self;
3527+
3528+
ret = pipe(pipe_fds);
3529+
if (ret < 0)
3530+
exit(1);
3531+
3532+
dup_fd = dup(pipe_fds[0]);
3533+
if (dup_fd < 0)
3534+
exit(1);
3535+
3536+
self = getpid();
3537+
3538+
ret = filecmp(self, self, pipe_fds[0], dup_fd);
3539+
if (ret)
3540+
exit(2);
3541+
3542+
exit(0);
3543+
}
3544+
3545+
pollfd.fd = listener;
3546+
pollfd.events = POLLIN | POLLOUT;
3547+
3548+
EXPECT_GT(poll(&pollfd, 1, -1), 0);
3549+
EXPECT_EQ(pollfd.revents, POLLIN);
3550+
3551+
EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
3552+
3553+
pollfd.fd = listener;
3554+
pollfd.events = POLLIN | POLLOUT;
3555+
3556+
EXPECT_GT(poll(&pollfd, 1, -1), 0);
3557+
EXPECT_EQ(pollfd.revents, POLLOUT);
3558+
3559+
EXPECT_EQ(req.data.nr, __NR_dup);
3560+
3561+
resp.id = req.id;
3562+
resp.flags = SECCOMP_USER_NOTIF_FLAG_CONTINUE;
3563+
3564+
/*
3565+
* Verify that setting SECCOMP_USER_NOTIF_FLAG_CONTINUE enforces other
3566+
* args be set to 0.
3567+
*/
3568+
resp.error = 0;
3569+
resp.val = USER_NOTIF_MAGIC;
3570+
EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
3571+
EXPECT_EQ(errno, EINVAL);
3572+
3573+
resp.error = USER_NOTIF_MAGIC;
3574+
resp.val = 0;
3575+
EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
3576+
EXPECT_EQ(errno, EINVAL);
3577+
3578+
resp.error = 0;
3579+
resp.val = 0;
3580+
EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0) {
3581+
if (errno == EINVAL)
3582+
XFAIL(goto skip, "Kernel does not support SECCOMP_USER_NOTIF_FLAG_CONTINUE");
3583+
}
3584+
3585+
skip:
3586+
EXPECT_EQ(waitpid(pid, &status, 0), pid);
3587+
EXPECT_EQ(true, WIFEXITED(status));
3588+
EXPECT_EQ(0, WEXITSTATUS(status)) {
3589+
if (WEXITSTATUS(status) == 2) {
3590+
XFAIL(return, "Kernel does not support kcmp() syscall");
3591+
return;
3592+
}
3593+
}
3594+
}
3595+
34893596
/*
34903597
* TODO:
34913598
* - add microbenchmarks

0 commit comments

Comments
 (0)