Loading debuggerd/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -195,6 +195,7 @@ cc_test { "libcutils", "libdebuggerd_client", "liblog", "libminijail", "libnativehelper" ], Loading debuggerd/Android.mk 0 → 100644 +23 −0 Original line number Diff line number Diff line 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) debuggerd/debuggerd_test.cpp +140 −3 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -77,8 +80,7 @@ constexpr char kWaitForGdbKey[] = "debug.debuggerd.wait_for_gdb"; }() #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"(\+)") 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) { Loading Loading @@ -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; Loading debuggerd/seccomp_policy/crash_dump.arm.policy 0 → 100644 +37 −0 Original line number Diff line number Diff line 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 debuggerd/seccomp_policy/crash_dump.arm64.policy 0 → 100644 +36 −0 Original line number Diff line number Diff line 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 Loading
debuggerd/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -195,6 +195,7 @@ cc_test { "libcutils", "libdebuggerd_client", "liblog", "libminijail", "libnativehelper" ], Loading
debuggerd/Android.mk 0 → 100644 +23 −0 Original line number Diff line number Diff line 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)
debuggerd/debuggerd_test.cpp +140 −3 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -77,8 +80,7 @@ constexpr char kWaitForGdbKey[] = "debug.debuggerd.wait_for_gdb"; }() #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"(\+)") 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) { Loading Loading @@ -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; Loading
debuggerd/seccomp_policy/crash_dump.arm.policy 0 → 100644 +37 −0 Original line number Diff line number Diff line 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
debuggerd/seccomp_policy/crash_dump.arm64.policy 0 → 100644 +36 −0 Original line number Diff line number Diff line 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