Commit adeeec84 authored by Kees Cook's avatar Kees Cook

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: default avatarJakub Kicinski <kuba@kernel.org>
Tested-by: default avatarWill Deacon <will@kernel.org>
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
parent 9d1587ad
...@@ -1510,6 +1510,7 @@ pid_t setup_trace_fixture(struct __test_metadata *_metadata, ...@@ -1510,6 +1510,7 @@ pid_t setup_trace_fixture(struct __test_metadata *_metadata,
return tracer_pid; return tracer_pid;
} }
void teardown_trace_fixture(struct __test_metadata *_metadata, void teardown_trace_fixture(struct __test_metadata *_metadata,
pid_t tracer) pid_t tracer)
{ {
...@@ -1789,7 +1790,7 @@ void change_syscall(struct __test_metadata *_metadata, ...@@ -1789,7 +1790,7 @@ void change_syscall(struct __test_metadata *_metadata,
EXPECT_EQ(0, ret); 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 status, void *args)
{ {
int ret; int ret;
...@@ -1866,6 +1867,24 @@ FIXTURE(TRACE_syscall) { ...@@ -1866,6 +1867,24 @@ FIXTURE(TRACE_syscall) {
pid_t tracer, mytid, mypid, parent; 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) FIXTURE_SETUP(TRACE_syscall)
{ {
struct sock_filter filter[] = { struct sock_filter filter[] = {
...@@ -1881,12 +1900,11 @@ FIXTURE_SETUP(TRACE_syscall) ...@@ -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_TRACE | 0x1005),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
}; };
struct sock_fprog prog = {
memset(&self->prog, 0, sizeof(self->prog)); .len = (unsigned short)ARRAY_SIZE(filter),
self->prog.filter = malloc(sizeof(filter)); .filter = filter,
ASSERT_NE(NULL, self->prog.filter); };
memcpy(self->prog.filter, filter, sizeof(filter)); long ret;
self->prog.len = (unsigned short)ARRAY_SIZE(filter);
/* Prepare some testable syscall results. */ /* Prepare some testable syscall results. */
self->mytid = syscall(__NR_gettid); self->mytid = syscall(__NR_gettid);
...@@ -1904,60 +1922,28 @@ FIXTURE_SETUP(TRACE_syscall) ...@@ -1904,60 +1922,28 @@ FIXTURE_SETUP(TRACE_syscall)
ASSERT_NE(self->parent, self->mypid); ASSERT_NE(self->parent, self->mypid);
/* Launch tracer. */ /* Launch tracer. */
self->tracer = setup_trace_fixture(_metadata, tracer_syscall, NULL, self->tracer = setup_trace_fixture(_metadata,
false); variant->use_ptrace ? tracer_ptrace
} : tracer_seccomp,
NULL, variant->use_ptrace);
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) ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
{ ASSERT_EQ(0, 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);
/* Tracer will redirect getpid to getppid. */
EXPECT_NE(self->mypid, syscall(__NR_getpid));
}
TEST_F(TRACE_syscall, ptrace_syscall_errno) if (variant->use_ptrace)
{ return;
/* 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. */ ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
EXPECT_SYSCALL_RETURN(-ESRCH, syscall(__NR_openat)); ASSERT_EQ(0, ret);
} }
TEST_F(TRACE_syscall, ptrace_syscall_faked) FIXTURE_TEARDOWN(TRACE_syscall)
{ {
/* Swap SECCOMP_RET_TRACE tracer for PTRACE_SYSCALL tracer. */
teardown_trace_fixture(_metadata, self->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) 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). */ /* getppid works as expected (no changes). */
EXPECT_EQ(self->parent, syscall(__NR_getppid)); EXPECT_EQ(self->parent, syscall(__NR_getppid));
EXPECT_NE(self->mypid, syscall(__NR_getppid)); EXPECT_NE(self->mypid, syscall(__NR_getppid));
...@@ -1965,14 +1951,6 @@ TEST_F(TRACE_syscall, syscall_allowed) ...@@ -1965,14 +1951,6 @@ TEST_F(TRACE_syscall, syscall_allowed)
TEST_F(TRACE_syscall, syscall_redirected) 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. */ /* getpid has been redirected to getppid as expected. */
EXPECT_EQ(self->parent, syscall(__NR_getpid)); EXPECT_EQ(self->parent, syscall(__NR_getpid));
EXPECT_NE(self->mypid, syscall(__NR_getpid)); EXPECT_NE(self->mypid, syscall(__NR_getpid));
...@@ -1980,33 +1958,17 @@ TEST_F(TRACE_syscall, syscall_redirected) ...@@ -1980,33 +1958,17 @@ TEST_F(TRACE_syscall, syscall_redirected)
TEST_F(TRACE_syscall, syscall_errno) TEST_F(TRACE_syscall, syscall_errno)
{ {
long ret; /* Tracer should skip the open syscall, resulting in ESRCH. */
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. */
EXPECT_SYSCALL_RETURN(-ESRCH, syscall(__NR_openat)); EXPECT_SYSCALL_RETURN(-ESRCH, syscall(__NR_openat));
} }
TEST_F(TRACE_syscall, syscall_faked) TEST_F(TRACE_syscall, syscall_faked)
{ {
long ret; /* Tracer skips the gettid syscall and store altered return value. */
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. */
EXPECT_SYSCALL_RETURN(45000, syscall(__NR_gettid)); 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[] = { struct sock_filter filter[] = {
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
...@@ -2021,14 +1983,7 @@ TEST_F(TRACE_syscall, skip_after_RET_TRACE) ...@@ -2021,14 +1983,7 @@ TEST_F(TRACE_syscall, skip_after_RET_TRACE)
}; };
long ret; long ret;
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); /* Install additional "errno on getppid" filter. */
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. */
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0); ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
ASSERT_EQ(0, ret); ASSERT_EQ(0, ret);
...@@ -2038,7 +1993,7 @@ TEST_F(TRACE_syscall, skip_after_RET_TRACE) ...@@ -2038,7 +1993,7 @@ TEST_F(TRACE_syscall, skip_after_RET_TRACE)
EXPECT_EQ(EPERM, errno); 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[] = { struct sock_filter filter[] = {
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
...@@ -2053,77 +2008,7 @@ TEST_F_SIGNAL(TRACE_syscall, kill_after_RET_TRACE, SIGSYS) ...@@ -2053,77 +2008,7 @@ TEST_F_SIGNAL(TRACE_syscall, kill_after_RET_TRACE, SIGSYS)
}; };
long ret; long ret;
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); /* Install additional "death on getppid" filter. */
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. */
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0); ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
ASSERT_EQ(0, ret); ASSERT_EQ(0, ret);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment