mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-28 15:13:55 +08:00
selftests/seccomp: Test thread vs process killing
This verifies that SECCOMP_RET_KILL_PROCESS is higher priority than SECCOMP_RET_KILL_THREAD. (This also moves a bunch of defines up earlier in the file to use them earlier.) Signed-off-by: Kees Cook <keescook@chromium.org> Reviewed-by: Tyler Hicks <tyhicks@canonical.com>
This commit is contained in:
parent
0466bdb99e
commit
f3e1821d9e
@ -68,7 +68,17 @@
|
||||
#define SECCOMP_MODE_FILTER 2
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_RET_KILL_THREAD
|
||||
#ifndef SECCOMP_RET_ALLOW
|
||||
struct seccomp_data {
|
||||
int nr;
|
||||
__u32 arch;
|
||||
__u64 instruction_pointer;
|
||||
__u64 args[6];
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_RET_KILL_PROCESS
|
||||
#define SECCOMP_RET_KILL_PROCESS 0x80000000U /* kill the process */
|
||||
#define SECCOMP_RET_KILL_THREAD 0x00000000U /* kill the thread */
|
||||
#endif
|
||||
#ifndef SECCOMP_RET_KILL
|
||||
@ -82,17 +92,53 @@
|
||||
#define SECCOMP_RET_LOG 0x7ffc0000U /* allow after logging */
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_RET_ACTION
|
||||
/* Masks for the return value sections. */
|
||||
#define SECCOMP_RET_ACTION 0x7fff0000U
|
||||
#define SECCOMP_RET_DATA 0x0000ffffU
|
||||
#ifndef __NR_seccomp
|
||||
# if defined(__i386__)
|
||||
# define __NR_seccomp 354
|
||||
# elif defined(__x86_64__)
|
||||
# define __NR_seccomp 317
|
||||
# elif defined(__arm__)
|
||||
# define __NR_seccomp 383
|
||||
# elif defined(__aarch64__)
|
||||
# define __NR_seccomp 277
|
||||
# elif defined(__hppa__)
|
||||
# define __NR_seccomp 338
|
||||
# elif defined(__powerpc__)
|
||||
# define __NR_seccomp 358
|
||||
# elif defined(__s390__)
|
||||
# define __NR_seccomp 348
|
||||
# else
|
||||
# warning "seccomp syscall number unknown for this architecture"
|
||||
# define __NR_seccomp 0xffff
|
||||
# endif
|
||||
#endif
|
||||
|
||||
struct seccomp_data {
|
||||
int nr;
|
||||
__u32 arch;
|
||||
__u64 instruction_pointer;
|
||||
__u64 args[6];
|
||||
};
|
||||
#ifndef SECCOMP_SET_MODE_STRICT
|
||||
#define SECCOMP_SET_MODE_STRICT 0
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_SET_MODE_FILTER
|
||||
#define SECCOMP_SET_MODE_FILTER 1
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_GET_ACTION_AVAIL
|
||||
#define SECCOMP_GET_ACTION_AVAIL 2
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_FILTER_FLAG_TSYNC
|
||||
#define SECCOMP_FILTER_FLAG_TSYNC 1
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_FILTER_FLAG_LOG
|
||||
#define SECCOMP_FILTER_FLAG_LOG 2
|
||||
#endif
|
||||
|
||||
#ifndef seccomp
|
||||
int seccomp(unsigned int op, unsigned int flags, void *args)
|
||||
{
|
||||
errno = 0;
|
||||
return syscall(__NR_seccomp, op, flags, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
@ -550,6 +596,117 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* This is a thread task to die via seccomp filter violation. */
|
||||
void *kill_thread(void *data)
|
||||
{
|
||||
bool die = (bool)data;
|
||||
|
||||
if (die) {
|
||||
prctl(PR_GET_SECCOMP, 0, 0, 0, 0);
|
||||
return (void *)SIBLING_EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return (void *)SIBLING_EXIT_UNKILLED;
|
||||
}
|
||||
|
||||
/* Prepare a thread that will kill itself or both of us. */
|
||||
void kill_thread_or_group(struct __test_metadata *_metadata, bool kill_process)
|
||||
{
|
||||
pthread_t thread;
|
||||
void *status;
|
||||
/* Kill only when calling __NR_prctl. */
|
||||
struct sock_filter filter_thread[] = {
|
||||
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
|
||||
offsetof(struct seccomp_data, nr)),
|
||||
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 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_thread = {
|
||||
.len = (unsigned short)ARRAY_SIZE(filter_thread),
|
||||
.filter = filter_thread,
|
||||
};
|
||||
struct sock_filter filter_process[] = {
|
||||
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
|
||||
offsetof(struct seccomp_data, nr)),
|
||||
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 0, 1),
|
||||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_PROCESS),
|
||||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
|
||||
};
|
||||
struct sock_fprog prog_process = {
|
||||
.len = (unsigned short)ARRAY_SIZE(filter_process),
|
||||
.filter = filter_process,
|
||||
};
|
||||
|
||||
ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
|
||||
TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
|
||||
}
|
||||
|
||||
ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0,
|
||||
kill_process ? &prog_process : &prog_thread));
|
||||
|
||||
/*
|
||||
* Add the KILL_THREAD rule again to make sure that the KILL_PROCESS
|
||||
* flag cannot be downgraded by a new filter.
|
||||
*/
|
||||
ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog_thread));
|
||||
|
||||
/* Start a thread that will exit immediately. */
|
||||
ASSERT_EQ(0, pthread_create(&thread, NULL, kill_thread, (void *)false));
|
||||
ASSERT_EQ(0, pthread_join(thread, &status));
|
||||
ASSERT_EQ(SIBLING_EXIT_UNKILLED, (unsigned long)status);
|
||||
|
||||
/* Start a thread that will die immediately. */
|
||||
ASSERT_EQ(0, pthread_create(&thread, NULL, kill_thread, (void *)true));
|
||||
ASSERT_EQ(0, pthread_join(thread, &status));
|
||||
ASSERT_NE(SIBLING_EXIT_FAILURE, (unsigned long)status);
|
||||
|
||||
/*
|
||||
* If we get here, only the spawned thread died. Let the parent know
|
||||
* the whole process didn't die (i.e. this thread, the spawner,
|
||||
* stayed running).
|
||||
*/
|
||||
exit(42);
|
||||
}
|
||||
|
||||
TEST(KILL_thread)
|
||||
{
|
||||
int status;
|
||||
pid_t child_pid;
|
||||
|
||||
child_pid = fork();
|
||||
ASSERT_LE(0, child_pid);
|
||||
if (child_pid == 0) {
|
||||
kill_thread_or_group(_metadata, false);
|
||||
_exit(38);
|
||||
}
|
||||
|
||||
ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
|
||||
|
||||
/* If only the thread was killed, we'll see exit 42. */
|
||||
ASSERT_TRUE(WIFEXITED(status));
|
||||
ASSERT_EQ(42, WEXITSTATUS(status));
|
||||
}
|
||||
|
||||
TEST(KILL_process)
|
||||
{
|
||||
int status;
|
||||
pid_t child_pid;
|
||||
|
||||
child_pid = fork();
|
||||
ASSERT_LE(0, child_pid);
|
||||
if (child_pid == 0) {
|
||||
kill_thread_or_group(_metadata, true);
|
||||
_exit(38);
|
||||
}
|
||||
|
||||
ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
|
||||
|
||||
/* If the entire process was killed, we'll see SIGSYS. */
|
||||
ASSERT_TRUE(WIFSIGNALED(status));
|
||||
ASSERT_EQ(SIGSYS, WTERMSIG(status));
|
||||
}
|
||||
|
||||
/* TODO(wad) add 64-bit versus 32-bit arg tests. */
|
||||
TEST(arg_out_of_range)
|
||||
{
|
||||
@ -1800,55 +1957,6 @@ TEST_F_SIGNAL(TRACE_syscall, kill_after_ptrace, SIGSYS)
|
||||
EXPECT_NE(self->mypid, syscall(__NR_getpid));
|
||||
}
|
||||
|
||||
#ifndef __NR_seccomp
|
||||
# if defined(__i386__)
|
||||
# define __NR_seccomp 354
|
||||
# elif defined(__x86_64__)
|
||||
# define __NR_seccomp 317
|
||||
# elif defined(__arm__)
|
||||
# define __NR_seccomp 383
|
||||
# elif defined(__aarch64__)
|
||||
# define __NR_seccomp 277
|
||||
# elif defined(__hppa__)
|
||||
# define __NR_seccomp 338
|
||||
# elif defined(__powerpc__)
|
||||
# define __NR_seccomp 358
|
||||
# elif defined(__s390__)
|
||||
# define __NR_seccomp 348
|
||||
# else
|
||||
# warning "seccomp syscall number unknown for this architecture"
|
||||
# define __NR_seccomp 0xffff
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_SET_MODE_STRICT
|
||||
#define SECCOMP_SET_MODE_STRICT 0
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_SET_MODE_FILTER
|
||||
#define SECCOMP_SET_MODE_FILTER 1
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_GET_ACTION_AVAIL
|
||||
#define SECCOMP_GET_ACTION_AVAIL 2
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_FILTER_FLAG_TSYNC
|
||||
#define SECCOMP_FILTER_FLAG_TSYNC 1
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_FILTER_FLAG_LOG
|
||||
#define SECCOMP_FILTER_FLAG_LOG 2
|
||||
#endif
|
||||
|
||||
#ifndef seccomp
|
||||
int seccomp(unsigned int op, unsigned int flags, void *args)
|
||||
{
|
||||
errno = 0;
|
||||
return syscall(__NR_seccomp, op, flags, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(seccomp_syscall)
|
||||
{
|
||||
struct sock_filter filter[] = {
|
||||
|
Loading…
Reference in New Issue
Block a user