Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris: "Highlights: - TPM core and driver updates/fixes - IPv6 security labeling (CALIPSO) - Lots of Apparmor fixes - Seccomp: remove 2-phase API, close hole where ptrace can change syscall #" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (156 commits) apparmor: fix SECURITY_APPARMOR_HASH_DEFAULT parameter handling tpm: Add TPM 2.0 support to the Nuvoton i2c driver (NPCT6xx family) tpm: Factor out common startup code tpm: use devm_add_action_or_reset tpm2_i2c_nuvoton: add irq validity check tpm: read burstcount from TPM_STS in one 32-bit transaction tpm: fix byte-order for the value read by tpm2_get_tpm_pt tpm_tis_core: convert max timeouts from msec to jiffies apparmor: fix arg_size computation for when setprocattr is null terminated apparmor: fix oops, validate buffer size in apparmor_setprocattr() apparmor: do not expose kernel stack apparmor: fix module parameters can be changed after policy is locked apparmor: fix oops in profile_unpack() when policy_db is not present apparmor: don't check for vmalloc_addr if kvzalloc() failed apparmor: add missing id bounds check on dfa verification apparmor: allow SYS_CAP_RESOURCE to be sufficient to prlimit another task apparmor: use list_next_entry instead of list_entry_next apparmor: fix refcount race when finding a child profile apparmor: fix ref count leak when profile sha1 hash is read apparmor: check that xindex is in trans_table bounds ...
This commit is contained in:
@@ -1021,8 +1021,8 @@ void tracer_stop(int sig)
|
||||
typedef void tracer_func_t(struct __test_metadata *_metadata,
|
||||
pid_t tracee, int status, void *args);
|
||||
|
||||
void tracer(struct __test_metadata *_metadata, int fd, pid_t tracee,
|
||||
tracer_func_t tracer_func, void *args)
|
||||
void start_tracer(struct __test_metadata *_metadata, int fd, pid_t tracee,
|
||||
tracer_func_t tracer_func, void *args, bool ptrace_syscall)
|
||||
{
|
||||
int ret = -1;
|
||||
struct sigaction action = {
|
||||
@@ -1042,12 +1042,16 @@ void tracer(struct __test_metadata *_metadata, int fd, pid_t tracee,
|
||||
/* Wait for attach stop */
|
||||
wait(NULL);
|
||||
|
||||
ret = ptrace(PTRACE_SETOPTIONS, tracee, NULL, PTRACE_O_TRACESECCOMP);
|
||||
ret = ptrace(PTRACE_SETOPTIONS, tracee, NULL, ptrace_syscall ?
|
||||
PTRACE_O_TRACESYSGOOD :
|
||||
PTRACE_O_TRACESECCOMP);
|
||||
ASSERT_EQ(0, ret) {
|
||||
TH_LOG("Failed to set PTRACE_O_TRACESECCOMP");
|
||||
kill(tracee, SIGKILL);
|
||||
}
|
||||
ptrace(PTRACE_CONT, tracee, NULL, 0);
|
||||
ret = ptrace(ptrace_syscall ? PTRACE_SYSCALL : PTRACE_CONT,
|
||||
tracee, NULL, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* Unblock the tracee */
|
||||
ASSERT_EQ(1, write(fd, "A", 1));
|
||||
@@ -1063,12 +1067,13 @@ void tracer(struct __test_metadata *_metadata, int fd, pid_t tracee,
|
||||
/* Child is dead. Time to go. */
|
||||
return;
|
||||
|
||||
/* Make sure this is a seccomp event. */
|
||||
ASSERT_EQ(true, IS_SECCOMP_EVENT(status));
|
||||
/* Check if this is a seccomp event. */
|
||||
ASSERT_EQ(!ptrace_syscall, IS_SECCOMP_EVENT(status));
|
||||
|
||||
tracer_func(_metadata, tracee, status, args);
|
||||
|
||||
ret = ptrace(PTRACE_CONT, tracee, NULL, NULL);
|
||||
ret = ptrace(ptrace_syscall ? PTRACE_SYSCALL : PTRACE_CONT,
|
||||
tracee, NULL, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
}
|
||||
/* Directly report the status of our test harness results. */
|
||||
@@ -1079,7 +1084,7 @@ void tracer(struct __test_metadata *_metadata, int fd, pid_t tracee,
|
||||
void cont_handler(int num)
|
||||
{ }
|
||||
pid_t setup_trace_fixture(struct __test_metadata *_metadata,
|
||||
tracer_func_t func, void *args)
|
||||
tracer_func_t func, void *args, bool ptrace_syscall)
|
||||
{
|
||||
char sync;
|
||||
int pipefd[2];
|
||||
@@ -1095,7 +1100,8 @@ pid_t setup_trace_fixture(struct __test_metadata *_metadata,
|
||||
signal(SIGALRM, cont_handler);
|
||||
if (tracer_pid == 0) {
|
||||
close(pipefd[0]);
|
||||
tracer(_metadata, pipefd[1], tracee, func, args);
|
||||
start_tracer(_metadata, pipefd[1], tracee, func, args,
|
||||
ptrace_syscall);
|
||||
syscall(__NR_exit, 0);
|
||||
}
|
||||
close(pipefd[1]);
|
||||
@@ -1177,7 +1183,7 @@ FIXTURE_SETUP(TRACE_poke)
|
||||
|
||||
/* Launch tracer. */
|
||||
self->tracer = setup_trace_fixture(_metadata, tracer_poke,
|
||||
&self->tracer_args);
|
||||
&self->tracer_args, false);
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(TRACE_poke)
|
||||
@@ -1399,6 +1405,29 @@ void tracer_syscall(struct __test_metadata *_metadata, pid_t tracee,
|
||||
|
||||
}
|
||||
|
||||
void tracer_ptrace(struct __test_metadata *_metadata, pid_t tracee,
|
||||
int status, void *args)
|
||||
{
|
||||
int ret, nr;
|
||||
unsigned long msg;
|
||||
static bool entry;
|
||||
|
||||
/* Make sure we got an empty message. */
|
||||
ret = ptrace(PTRACE_GETEVENTMSG, tracee, NULL, &msg);
|
||||
EXPECT_EQ(0, ret);
|
||||
EXPECT_EQ(0, msg);
|
||||
|
||||
/* The only way to tell PTRACE_SYSCALL entry/exit is by counting. */
|
||||
entry = !entry;
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
nr = get_syscall(_metadata, tracee);
|
||||
|
||||
if (nr == __NR_getpid)
|
||||
change_syscall(_metadata, tracee, __NR_getppid);
|
||||
}
|
||||
|
||||
FIXTURE_DATA(TRACE_syscall) {
|
||||
struct sock_fprog prog;
|
||||
pid_t tracer, mytid, mypid, parent;
|
||||
@@ -1440,7 +1469,8 @@ FIXTURE_SETUP(TRACE_syscall)
|
||||
ASSERT_NE(self->parent, self->mypid);
|
||||
|
||||
/* Launch tracer. */
|
||||
self->tracer = setup_trace_fixture(_metadata, tracer_syscall, NULL);
|
||||
self->tracer = setup_trace_fixture(_metadata, tracer_syscall, NULL,
|
||||
false);
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(TRACE_syscall)
|
||||
@@ -1500,6 +1530,130 @@ TEST_F(TRACE_syscall, syscall_dropped)
|
||||
EXPECT_NE(self->mytid, syscall(__NR_gettid));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, skip_after_RET_TRACE)
|
||||
{
|
||||
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;
|
||||
|
||||
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. */
|
||||
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_RET_TRACE, 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;
|
||||
|
||||
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. */
|
||||
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));
|
||||
}
|
||||
|
||||
#ifndef __NR_seccomp
|
||||
# if defined(__i386__)
|
||||
# define __NR_seccomp 354
|
||||
|
Reference in New Issue
Block a user