Skip to content

Commit

Permalink
selftests/seccomp: Report event mismatches more clearly
Browse files Browse the repository at this point in the history
When running under tracer, more explicitly report the status and event
mismatches to help with debugging. Additionally add an "immediate kill"
test when under tracing to verify that fatal SIGSYS behaves the same
under ptrace or seccomp tracing.

Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Will Drewry <wad@chromium.org>
Cc: linux-kselftest@vger.kernel.org
Signed-off-by: Kees Cook <keescook@chromium.org>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Link: https://lore.kernel.org/r/20211103163039.2104830-3-keescook@chromium.org
  • Loading branch information
Kees Cook committed Nov 3, 2021
1 parent 48d5fd0 commit 1e6d69c
Showing 1 changed file with 49 additions and 5 deletions.
54 changes: 49 additions & 5 deletions tools/testing/selftests/seccomp/seccomp_bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1487,7 +1487,7 @@ TEST_F(precedence, log_is_fifth_in_any_order)
#define PTRACE_EVENT_SECCOMP 7
#endif

#define IS_SECCOMP_EVENT(status) ((status >> 16) == PTRACE_EVENT_SECCOMP)
#define PTRACE_EVENT_MASK(status) ((status) >> 16)
bool tracer_running;
void tracer_stop(int sig)
{
Expand Down Expand Up @@ -1539,12 +1539,22 @@ void start_tracer(struct __test_metadata *_metadata, int fd, pid_t tracee,

if (wait(&status) != tracee)
continue;
if (WIFSIGNALED(status) || WIFEXITED(status))
/* Child is dead. Time to go. */

if (WIFSIGNALED(status)) {
/* Child caught a fatal signal. */
return;
}
if (WIFEXITED(status)) {
/* Child exited with code. */
return;
}

/* Check if this is a seccomp event. */
ASSERT_EQ(!ptrace_syscall, IS_SECCOMP_EVENT(status));
/* Check if we got an expected event. */
ASSERT_EQ(WIFCONTINUED(status), false);
ASSERT_EQ(WIFSTOPPED(status), true);
ASSERT_EQ(WSTOPSIG(status) & SIGTRAP, SIGTRAP) {
TH_LOG("Unexpected WSTOPSIG: %d", WSTOPSIG(status));
}

tracer_func(_metadata, tracee, status, args);

Expand Down Expand Up @@ -1961,6 +1971,11 @@ void tracer_seccomp(struct __test_metadata *_metadata, pid_t tracee,
int ret;
unsigned long msg;

EXPECT_EQ(PTRACE_EVENT_MASK(status), PTRACE_EVENT_SECCOMP) {
TH_LOG("Unexpected ptrace event: %d", PTRACE_EVENT_MASK(status));
return;
}

/* Make sure we got the right message. */
ret = ptrace(PTRACE_GETEVENTMSG, tracee, NULL, &msg);
EXPECT_EQ(0, ret);
Expand Down Expand Up @@ -2011,6 +2026,11 @@ void tracer_ptrace(struct __test_metadata *_metadata, pid_t tracee,
long *syscall_nr = NULL, *syscall_ret = NULL;
FIXTURE_DATA(TRACE_syscall) *self = args;

EXPECT_EQ(WSTOPSIG(status) & 0x80, 0x80) {
TH_LOG("Unexpected WSTOPSIG: %d", WSTOPSIG(status));
return;
}

/*
* The traditional way to tell PTRACE_SYSCALL entry/exit
* is by counting.
Expand Down Expand Up @@ -2128,6 +2148,7 @@ FIXTURE_SETUP(TRACE_syscall)
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
ASSERT_EQ(0, ret);

/* Do not install seccomp rewrite filters, as we'll use ptrace instead. */
if (variant->use_ptrace)
return;

Expand Down Expand Up @@ -2186,6 +2207,29 @@ TEST_F(TRACE_syscall, syscall_faked)
EXPECT_SYSCALL_RETURN(45000, syscall(__NR_gettid));
}

TEST_F_SIGNAL(TRACE_syscall, kill_immediate, SIGSYS)
{
struct sock_filter filter[] = {
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
offsetof(struct seccomp_data, nr)),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_mknodat, 0, 1),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_THREAD),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};
struct sock_fprog prog = {
.len = (unsigned short)ARRAY_SIZE(filter),
.filter = filter,
};
long ret;

/* Install "kill on mknodat" filter. */
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
ASSERT_EQ(0, ret);

/* This should immediately die with SIGSYS, regardless of tracer. */
EXPECT_EQ(-1, syscall(__NR_mknodat, -1, NULL, 0, 0));
}

TEST_F(TRACE_syscall, skip_after)
{
struct sock_filter filter[] = {
Expand Down

0 comments on commit 1e6d69c

Please sign in to comment.