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:
parent
55feb241b1
commit
e04ca2794a
9 changed files with 384 additions and 3 deletions
|
@ -195,6 +195,7 @@ cc_test {
|
|||
"libcutils",
|
||||
"libdebuggerd_client",
|
||||
"liblog",
|
||||
"libminijail",
|
||||
"libnativehelper"
|
||||
],
|
||||
|
||||
|
|
23
debuggerd/Android.mk
Normal file
23
debuggerd/Android.mk
Normal 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)
|
|
@ -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;
|
||||
|
|
37
debuggerd/seccomp_policy/crash_dump.arm.policy
Normal file
37
debuggerd/seccomp_policy/crash_dump.arm.policy
Normal 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
|
36
debuggerd/seccomp_policy/crash_dump.arm64.policy
Normal file
36
debuggerd/seccomp_policy/crash_dump.arm64.policy
Normal 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
|
64
debuggerd/seccomp_policy/crash_dump.policy.def
Normal file
64
debuggerd/seccomp_policy/crash_dump.policy.def
Normal 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
|
37
debuggerd/seccomp_policy/crash_dump.x86.policy
Normal file
37
debuggerd/seccomp_policy/crash_dump.x86.policy
Normal 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
|
36
debuggerd/seccomp_policy/crash_dump.x86_64.policy
Normal file
36
debuggerd/seccomp_policy/crash_dump.x86_64.policy
Normal 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
|
10
debuggerd/seccomp_policy/generate.sh
Executable file
10
debuggerd/seccomp_policy/generate.sh
Executable 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
|
Loading…
Reference in a new issue