debuggerd: add seccomp policies and tests.

Bug: http://b/38508369
Test: debuggerd_test32/64 on walleye and aosp_x86_64
Change-Id: I7e69e37bcd1823d271b9f2b0a13b8c9cba9a8e84
This commit is contained in:
Josh Gao 2018-01-16 15:38:17 -08:00
parent 55feb241b1
commit e04ca2794a
9 changed files with 384 additions and 3 deletions

View file

@ -195,6 +195,7 @@ cc_test {
"libcutils",
"libdebuggerd_client",
"liblog",
"libminijail",
"libnativehelper"
],

23
debuggerd/Android.mk Normal file
View file

@ -0,0 +1,23 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := crash_dump.policy
LOCAL_MODULE_CLASS := ETC
LOCAL_MULTILIB := both
ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64))
LOCAL_MODULE_STEM_32 := crash_dump.arm.policy
LOCAL_MODULE_STEM_64 := crash_dump.arm64.policy
endif
ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64))
LOCAL_MODULE_STEM_32 := crash_dump.x86.policy
LOCAL_MODULE_STEM_64 := crash_dump.x86_64.policy
endif
LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
LOCAL_SRC_FILES_arm := seccomp_policy/crash_dump.arm.policy
LOCAL_SRC_FILES_arm64 := seccomp_policy/crash_dump.arm64.policy
LOCAL_SRC_FILES_x86 := seccomp_policy/crash_dump.x86.policy
LOCAL_SRC_FILES_x86_64 := seccomp_policy/crash_dump.x86_64.policy
include $(BUILD_PREBUILT)

View file

@ -41,6 +41,9 @@
#include <cutils/sockets.h>
#include <gtest/gtest.h>
#include <libminijail.h>
#include <scoped_minijail.h>
#include "debuggerd/handler.h"
#include "protocol.h"
#include "tombstoned/tombstoned.h"
@ -76,9 +79,8 @@ constexpr char kWaitForGdbKey[] = "debug.debuggerd.wait_for_gdb";
return value; \
}()
#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX \
R"(/libc.so \()" frame_name R"(\+)")
#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ \S+ \()" frame_name R"(\+)");
static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
InterceptStatus* status, DebuggerdDumpType intercept_type) {
@ -565,6 +567,141 @@ TEST_F(CrasherTest, fake_pid) {
ASSERT_BACKTRACE_FRAME(result, "tgkill");
}
static const char* const kDebuggerdSeccompPolicy =
"/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
pid_t seccomp_fork() {
unique_fd policy_fd(open(kDebuggerdSeccompPolicy, O_RDONLY | O_CLOEXEC));
if (policy_fd == -1) {
LOG(FATAL) << "failed to open policy " << kDebuggerdSeccompPolicy;
}
ScopedMinijail jail{minijail_new()};
if (!jail) {
LOG(FATAL) << "failed to create minijail";
}
minijail_no_new_privs(jail.get());
minijail_log_seccomp_filter_failures(jail.get());
minijail_use_seccomp_filter(jail.get());
minijail_parse_seccomp_filters_from_fd(jail.get(), policy_fd.release());
pid_t result = fork();
if (result == -1) {
return result;
} else if (result != 0) {
return result;
}
// Spawn and detach a thread that spins forever.
std::atomic<bool> thread_ready(false);
std::thread thread([&jail, &thread_ready]() {
minijail_enter(jail.get());
thread_ready = true;
for (;;)
;
});
thread.detach();
while (!thread_ready) {
continue;
}
minijail_enter(jail.get());
return result;
}
TEST_F(CrasherTest, seccomp_crash) {
int intercept_result;
unique_fd output_fd;
StartProcess([]() { abort(); }, &seccomp_fork);
StartIntercept(&output_fd);
FinishCrasher();
AssertDeath(SIGABRT);
FinishIntercept(&intercept_result);
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
std::string result;
ConsumeFd(std::move(output_fd), &result);
ASSERT_BACKTRACE_FRAME(result, "abort");
}
__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
siginfo_t siginfo;
siginfo.si_code = SI_QUEUE;
siginfo.si_pid = getpid();
siginfo.si_uid = getuid();
if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
PLOG(FATAL) << "invalid dump type";
}
siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), DEBUGGER_SIGNAL, &siginfo) != 0) {
PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
return false;
}
return true;
}
TEST_F(CrasherTest, seccomp_tombstone) {
int intercept_result;
unique_fd output_fd;
static const auto dump_type = kDebuggerdTombstone;
StartProcess(
[]() {
raise_debugger_signal(dump_type);
_exit(0);
},
&seccomp_fork);
StartIntercept(&output_fd, dump_type);
FinishCrasher();
AssertDeath(0);
FinishIntercept(&intercept_result);
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
std::string result;
ConsumeFd(std::move(output_fd), &result);
ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
}
TEST_F(CrasherTest, seccomp_backtrace) {
int intercept_result;
unique_fd output_fd;
static const auto dump_type = kDebuggerdNativeBacktrace;
StartProcess(
[]() {
raise_debugger_signal(dump_type);
_exit(0);
},
&seccomp_fork);
StartIntercept(&output_fd, dump_type);
FinishCrasher();
AssertDeath(0);
FinishIntercept(&intercept_result);
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
std::string result;
ConsumeFd(std::move(output_fd), &result);
ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
}
TEST_F(CrasherTest, seccomp_crash_logcat) {
StartProcess([]() { abort(); }, &seccomp_fork);
FinishCrasher();
// Make sure we don't get SIGSYS when trying to dump a crash to logcat.
AssertDeath(SIGABRT);
}
TEST_F(CrasherTest, competing_tracer) {
int intercept_result;
unique_fd output_fd;

View file

@ -0,0 +1,37 @@
read: 1
write: 1
exit: 1
rt_sigreturn: 1
sigreturn: 1
exit_group: 1
clock_gettime: 1
gettimeofday: 1
futex: 1
getrandom: 1
getpid: 1
gettid: 1
ppoll: 1
pipe2: 1
openat: 1
dup: 1
close: 1
lseek: 1
getdents64: 1
faccessat: 1
recvmsg: 1
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
rt_tgsigqueueinfo: 1
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
madvise: 1
mprotect: arg2 in PROT_READ|PROT_WRITE
munmap: 1
getuid32: 1
fstat64: 1
mmap2: arg2 in PROT_READ|PROT_WRITE
sigaction: 1
geteuid32: 1
getgid32: 1
getegid32: 1
getgroups32: 1

View file

@ -0,0 +1,36 @@
read: 1
write: 1
exit: 1
rt_sigreturn: 1
exit_group: 1
clock_gettime: 1
gettimeofday: 1
futex: 1
getrandom: 1
getpid: 1
gettid: 1
ppoll: 1
pipe2: 1
openat: 1
dup: 1
close: 1
lseek: 1
getdents64: 1
faccessat: 1
recvmsg: 1
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
rt_tgsigqueueinfo: 1
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
madvise: 1
mprotect: arg2 in PROT_READ|PROT_WRITE
munmap: 1
getuid: 1
fstat: 1
mmap: arg2 in PROT_READ|PROT_WRITE
rt_sigaction: 1
geteuid: 1
getgid: 1
getegid: 1
getgroups: 1

View file

@ -0,0 +1,64 @@
// SECCOMP_MODE_STRICT
read: 1
write: 1
exit: 1
rt_sigreturn: 1
#if !defined(__LP64__)
sigreturn: 1
#endif
exit_group: 1
clock_gettime: 1
gettimeofday: 1
futex: 1
getrandom: 1
getpid: 1
gettid: 1
ppoll: 1
pipe2: 1
openat: 1
dup: 1
close: 1
lseek: 1
getdents64: 1
faccessat: 1
recvmsg: 1
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
rt_tgsigqueueinfo: 1
#define PR_SET_VMA 0x53564d41
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == PR_SET_VMA
madvise: 1
mprotect: arg2 in PROT_READ|PROT_WRITE
munmap: 1
#if defined(__LP64__)
getuid: 1
fstat: 1
mmap: arg2 in PROT_READ|PROT_WRITE
rt_sigaction: 1
#else
getuid32: 1
fstat64: 1
mmap2: arg2 in PROT_READ|PROT_WRITE
sigaction: 1
#endif
// Needed for logging.
#if defined(__LP64__)
geteuid: 1
getgid: 1
getegid: 1
getgroups: 1
#else
geteuid32: 1
getgid32: 1
getegid32: 1
getgroups32: 1
#endif

View file

@ -0,0 +1,37 @@
read: 1
write: 1
exit: 1
rt_sigreturn: 1
sigreturn: 1
exit_group: 1
clock_gettime: 1
gettimeofday: 1
futex: 1
getrandom: 1
getpid: 1
gettid: 1
ppoll: 1
pipe2: 1
openat: 1
dup: 1
close: 1
lseek: 1
getdents64: 1
faccessat: 1
recvmsg: 1
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
rt_tgsigqueueinfo: 1
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
madvise: 1
mprotect: arg2 in PROT_READ|PROT_WRITE
munmap: 1
getuid32: 1
fstat64: 1
mmap2: arg2 in PROT_READ|PROT_WRITE
sigaction: 1
geteuid32: 1
getgid32: 1
getegid32: 1
getgroups32: 1

View file

@ -0,0 +1,36 @@
read: 1
write: 1
exit: 1
rt_sigreturn: 1
exit_group: 1
clock_gettime: 1
gettimeofday: 1
futex: 1
getrandom: 1
getpid: 1
gettid: 1
ppoll: 1
pipe2: 1
openat: 1
dup: 1
close: 1
lseek: 1
getdents64: 1
faccessat: 1
recvmsg: 1
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
rt_tgsigqueueinfo: 1
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
madvise: 1
mprotect: arg2 in PROT_READ|PROT_WRITE
munmap: 1
getuid: 1
fstat: 1
mmap: arg2 in PROT_READ|PROT_WRITE
rt_sigaction: 1
geteuid: 1
getgid: 1
getegid: 1
getgroups: 1

View file

@ -0,0 +1,10 @@
#!/bin/bash
set -ex
cd "$(dirname "$0")"
CPP='cpp -undef -E -P crash_dump.policy.def'
$CPP -D__arm__ -o crash_dump.arm.policy
$CPP -D__aarch64__ -D__LP64__ -o crash_dump.arm64.policy
$CPP -D__i386__ -o crash_dump.x86.policy
$CPP -D__x86_64__ -D__LP64__ -o crash_dump.x86_64.policy