selftests/seccomp: Refactor to use fixture variants
Now that the selftest harness has variants, use them to eliminate a bunch of copy/paste duplication. Reviewed-by: Jakub Kicinski <kuba@kernel.org> Tested-by: Will Deacon <will@kernel.org> Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
parent
9d1587adcc
commit
adeeec8472
|
@ -1510,6 +1510,7 @@ pid_t setup_trace_fixture(struct __test_metadata *_metadata,
|
|||
|
||||
return tracer_pid;
|
||||
}
|
||||
|
||||
void teardown_trace_fixture(struct __test_metadata *_metadata,
|
||||
pid_t tracer)
|
||||
{
|
||||
|
@ -1789,7 +1790,7 @@ void change_syscall(struct __test_metadata *_metadata,
|
|||
EXPECT_EQ(0, ret);
|
||||
}
|
||||
|
||||
void tracer_syscall(struct __test_metadata *_metadata, pid_t tracee,
|
||||
void tracer_seccomp(struct __test_metadata *_metadata, pid_t tracee,
|
||||
int status, void *args)
|
||||
{
|
||||
int ret;
|
||||
|
@ -1866,6 +1867,24 @@ FIXTURE(TRACE_syscall) {
|
|||
pid_t tracer, mytid, mypid, parent;
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT(TRACE_syscall) {
|
||||
/*
|
||||
* All of the SECCOMP_RET_TRACE behaviors can be tested with either
|
||||
* SECCOMP_RET_TRACE+PTRACE_CONT or plain ptrace()+PTRACE_SYSCALL.
|
||||
* This indicates if we should use SECCOMP_RET_TRACE (false), or
|
||||
* ptrace (true).
|
||||
*/
|
||||
bool use_ptrace;
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(TRACE_syscall, ptrace) {
|
||||
.use_ptrace = true,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(TRACE_syscall, seccomp) {
|
||||
.use_ptrace = false,
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(TRACE_syscall)
|
||||
{
|
||||
struct sock_filter filter[] = {
|
||||
|
@ -1881,12 +1900,11 @@ FIXTURE_SETUP(TRACE_syscall)
|
|||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1005),
|
||||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
|
||||
};
|
||||
|
||||
memset(&self->prog, 0, sizeof(self->prog));
|
||||
self->prog.filter = malloc(sizeof(filter));
|
||||
ASSERT_NE(NULL, self->prog.filter);
|
||||
memcpy(self->prog.filter, filter, sizeof(filter));
|
||||
self->prog.len = (unsigned short)ARRAY_SIZE(filter);
|
||||
struct sock_fprog prog = {
|
||||
.len = (unsigned short)ARRAY_SIZE(filter),
|
||||
.filter = filter,
|
||||
};
|
||||
long ret;
|
||||
|
||||
/* Prepare some testable syscall results. */
|
||||
self->mytid = syscall(__NR_gettid);
|
||||
|
@ -1904,60 +1922,28 @@ FIXTURE_SETUP(TRACE_syscall)
|
|||
ASSERT_NE(self->parent, self->mypid);
|
||||
|
||||
/* Launch tracer. */
|
||||
self->tracer = setup_trace_fixture(_metadata, tracer_syscall, NULL,
|
||||
false);
|
||||
self->tracer = setup_trace_fixture(_metadata,
|
||||
variant->use_ptrace ? tracer_ptrace
|
||||
: tracer_seccomp,
|
||||
NULL, variant->use_ptrace);
|
||||
|
||||
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
if (variant->use_ptrace)
|
||||
return;
|
||||
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(TRACE_syscall)
|
||||
{
|
||||
teardown_trace_fixture(_metadata, self->tracer);
|
||||
if (self->prog.filter)
|
||||
free(self->prog.filter);
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, ptrace_syscall_redirected)
|
||||
{
|
||||
/* Swap SECCOMP_RET_TRACE tracer for PTRACE_SYSCALL tracer. */
|
||||
teardown_trace_fixture(_metadata, self->tracer);
|
||||
self->tracer = setup_trace_fixture(_metadata, tracer_ptrace, NULL,
|
||||
true);
|
||||
|
||||
/* Tracer will redirect getpid to getppid. */
|
||||
EXPECT_NE(self->mypid, syscall(__NR_getpid));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, ptrace_syscall_errno)
|
||||
{
|
||||
/* Swap SECCOMP_RET_TRACE tracer for PTRACE_SYSCALL tracer. */
|
||||
teardown_trace_fixture(_metadata, self->tracer);
|
||||
self->tracer = setup_trace_fixture(_metadata, tracer_ptrace, NULL,
|
||||
true);
|
||||
|
||||
/* Tracer should skip the open syscall, resulting in ESRCH. */
|
||||
EXPECT_SYSCALL_RETURN(-ESRCH, syscall(__NR_openat));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, ptrace_syscall_faked)
|
||||
{
|
||||
/* Swap SECCOMP_RET_TRACE tracer for PTRACE_SYSCALL tracer. */
|
||||
teardown_trace_fixture(_metadata, self->tracer);
|
||||
self->tracer = setup_trace_fixture(_metadata, tracer_ptrace, NULL,
|
||||
true);
|
||||
|
||||
/* Tracer should skip the gettid syscall, resulting fake pid. */
|
||||
EXPECT_SYSCALL_RETURN(45000, syscall(__NR_gettid));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, syscall_allowed)
|
||||
{
|
||||
long ret;
|
||||
|
||||
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* getppid works as expected (no changes). */
|
||||
EXPECT_EQ(self->parent, syscall(__NR_getppid));
|
||||
EXPECT_NE(self->mypid, syscall(__NR_getppid));
|
||||
|
@ -1965,14 +1951,6 @@ TEST_F(TRACE_syscall, syscall_allowed)
|
|||
|
||||
TEST_F(TRACE_syscall, syscall_redirected)
|
||||
{
|
||||
long ret;
|
||||
|
||||
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* getpid has been redirected to getppid as expected. */
|
||||
EXPECT_EQ(self->parent, syscall(__NR_getpid));
|
||||
EXPECT_NE(self->mypid, syscall(__NR_getpid));
|
||||
|
@ -1980,33 +1958,17 @@ TEST_F(TRACE_syscall, syscall_redirected)
|
|||
|
||||
TEST_F(TRACE_syscall, syscall_errno)
|
||||
{
|
||||
long ret;
|
||||
|
||||
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* openat has been skipped and an errno return. */
|
||||
/* Tracer should skip the open syscall, resulting in ESRCH. */
|
||||
EXPECT_SYSCALL_RETURN(-ESRCH, syscall(__NR_openat));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, syscall_faked)
|
||||
{
|
||||
long ret;
|
||||
|
||||
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* gettid has been skipped and an altered return value stored. */
|
||||
/* Tracer skips the gettid syscall and store altered return value. */
|
||||
EXPECT_SYSCALL_RETURN(45000, syscall(__NR_gettid));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, skip_after_RET_TRACE)
|
||||
TEST_F(TRACE_syscall, skip_after)
|
||||
{
|
||||
struct sock_filter filter[] = {
|
||||
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
|
||||
|
@ -2021,14 +1983,7 @@ TEST_F(TRACE_syscall, skip_after_RET_TRACE)
|
|||
};
|
||||
long ret;
|
||||
|
||||
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* Install fixture filter. */
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* Install "errno on getppid" filter. */
|
||||
/* Install additional "errno on getppid" filter. */
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
|
@ -2038,7 +1993,7 @@ TEST_F(TRACE_syscall, skip_after_RET_TRACE)
|
|||
EXPECT_EQ(EPERM, errno);
|
||||
}
|
||||
|
||||
TEST_F_SIGNAL(TRACE_syscall, kill_after_RET_TRACE, SIGSYS)
|
||||
TEST_F_SIGNAL(TRACE_syscall, kill_after, SIGSYS)
|
||||
{
|
||||
struct sock_filter filter[] = {
|
||||
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
|
||||
|
@ -2053,77 +2008,7 @@ TEST_F_SIGNAL(TRACE_syscall, kill_after_RET_TRACE, SIGSYS)
|
|||
};
|
||||
long ret;
|
||||
|
||||
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* Install fixture filter. */
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* Install "death on getppid" filter. */
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* Tracer will redirect getpid to getppid, and we should die. */
|
||||
EXPECT_NE(self->mypid, syscall(__NR_getpid));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, skip_after_ptrace)
|
||||
{
|
||||
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_getppid, 0, 1),
|
||||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | EPERM),
|
||||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
|
||||
};
|
||||
struct sock_fprog prog = {
|
||||
.len = (unsigned short)ARRAY_SIZE(filter),
|
||||
.filter = filter,
|
||||
};
|
||||
long ret;
|
||||
|
||||
/* Swap SECCOMP_RET_TRACE tracer for PTRACE_SYSCALL tracer. */
|
||||
teardown_trace_fixture(_metadata, self->tracer);
|
||||
self->tracer = setup_trace_fixture(_metadata, tracer_ptrace, NULL,
|
||||
true);
|
||||
|
||||
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* Install "errno on getppid" filter. */
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* Tracer will redirect getpid to getppid, and we should see EPERM. */
|
||||
EXPECT_EQ(-1, syscall(__NR_getpid));
|
||||
EXPECT_EQ(EPERM, errno);
|
||||
}
|
||||
|
||||
TEST_F_SIGNAL(TRACE_syscall, kill_after_ptrace, 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_getppid, 0, 1),
|
||||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
|
||||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
|
||||
};
|
||||
struct sock_fprog prog = {
|
||||
.len = (unsigned short)ARRAY_SIZE(filter),
|
||||
.filter = filter,
|
||||
};
|
||||
long ret;
|
||||
|
||||
/* Swap SECCOMP_RET_TRACE tracer for PTRACE_SYSCALL tracer. */
|
||||
teardown_trace_fixture(_metadata, self->tracer);
|
||||
self->tracer = setup_trace_fixture(_metadata, tracer_ptrace, NULL,
|
||||
true);
|
||||
|
||||
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* Install "death on getppid" filter. */
|
||||
/* Install additional "death on getppid" filter. */
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
|
|
Loading…
Reference in New Issue