summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'debuggerd/debuggerd_test.cpp')
-rw-r--r--debuggerd/debuggerd_test.cpp143
1 files changed, 140 insertions, 3 deletions
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 939f4d257..f8b4bad6e 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -41,6 +41,9 @@
41#include <cutils/sockets.h> 41#include <cutils/sockets.h>
42#include <gtest/gtest.h> 42#include <gtest/gtest.h>
43 43
44#include <libminijail.h>
45#include <scoped_minijail.h>
46
44#include "debuggerd/handler.h" 47#include "debuggerd/handler.h"
45#include "protocol.h" 48#include "protocol.h"
46#include "tombstoned/tombstoned.h" 49#include "tombstoned/tombstoned.h"
@@ -76,9 +79,8 @@ constexpr char kWaitForGdbKey[] = "debug.debuggerd.wait_for_gdb";
76 return value; \ 79 return value; \
77 }() 80 }()
78 81
79#define ASSERT_BACKTRACE_FRAME(result, frame_name) \ 82#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
80 ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX \ 83 ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ \S+ \()" frame_name R"(\+)");
81 R"(/libc.so \()" frame_name R"(\+)")
82 84
83static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd, 85static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
84 InterceptStatus* status, DebuggerdDumpType intercept_type) { 86 InterceptStatus* status, DebuggerdDumpType intercept_type) {
@@ -565,6 +567,141 @@ TEST_F(CrasherTest, fake_pid) {
565 ASSERT_BACKTRACE_FRAME(result, "tgkill"); 567 ASSERT_BACKTRACE_FRAME(result, "tgkill");
566} 568}
567 569
570static const char* const kDebuggerdSeccompPolicy =
571 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
572
573pid_t seccomp_fork() {
574 unique_fd policy_fd(open(kDebuggerdSeccompPolicy, O_RDONLY | O_CLOEXEC));
575 if (policy_fd == -1) {
576 LOG(FATAL) << "failed to open policy " << kDebuggerdSeccompPolicy;
577 }
578
579 ScopedMinijail jail{minijail_new()};
580 if (!jail) {
581 LOG(FATAL) << "failed to create minijail";
582 }
583
584 minijail_no_new_privs(jail.get());
585 minijail_log_seccomp_filter_failures(jail.get());
586 minijail_use_seccomp_filter(jail.get());
587 minijail_parse_seccomp_filters_from_fd(jail.get(), policy_fd.release());
588
589 pid_t result = fork();
590 if (result == -1) {
591 return result;
592 } else if (result != 0) {
593 return result;
594 }
595
596 // Spawn and detach a thread that spins forever.
597 std::atomic<bool> thread_ready(false);
598 std::thread thread([&jail, &thread_ready]() {
599 minijail_enter(jail.get());
600 thread_ready = true;
601 for (;;)
602 ;
603 });
604 thread.detach();
605
606 while (!thread_ready) {
607 continue;
608 }
609
610 minijail_enter(jail.get());
611 return result;
612}
613
614TEST_F(CrasherTest, seccomp_crash) {
615 int intercept_result;
616 unique_fd output_fd;
617
618 StartProcess([]() { abort(); }, &seccomp_fork);
619
620 StartIntercept(&output_fd);
621 FinishCrasher();
622 AssertDeath(SIGABRT);
623 FinishIntercept(&intercept_result);
624 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
625
626 std::string result;
627 ConsumeFd(std::move(output_fd), &result);
628 ASSERT_BACKTRACE_FRAME(result, "abort");
629}
630
631__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
632 siginfo_t siginfo;
633 siginfo.si_code = SI_QUEUE;
634 siginfo.si_pid = getpid();
635 siginfo.si_uid = getuid();
636
637 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
638 PLOG(FATAL) << "invalid dump type";
639 }
640
641 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
642
643 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), DEBUGGER_SIGNAL, &siginfo) != 0) {
644 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
645 return false;
646 }
647
648 return true;
649}
650
651TEST_F(CrasherTest, seccomp_tombstone) {
652 int intercept_result;
653 unique_fd output_fd;
654
655 static const auto dump_type = kDebuggerdTombstone;
656 StartProcess(
657 []() {
658 raise_debugger_signal(dump_type);
659 _exit(0);
660 },
661 &seccomp_fork);
662
663 StartIntercept(&output_fd, dump_type);
664 FinishCrasher();
665 AssertDeath(0);
666 FinishIntercept(&intercept_result);
667 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
668
669 std::string result;
670 ConsumeFd(std::move(output_fd), &result);
671 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
672}
673
674TEST_F(CrasherTest, seccomp_backtrace) {
675 int intercept_result;
676 unique_fd output_fd;
677
678 static const auto dump_type = kDebuggerdNativeBacktrace;
679 StartProcess(
680 []() {
681 raise_debugger_signal(dump_type);
682 _exit(0);
683 },
684 &seccomp_fork);
685
686 StartIntercept(&output_fd, dump_type);
687 FinishCrasher();
688 AssertDeath(0);
689 FinishIntercept(&intercept_result);
690 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
691
692 std::string result;
693 ConsumeFd(std::move(output_fd), &result);
694 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
695}
696
697TEST_F(CrasherTest, seccomp_crash_logcat) {
698 StartProcess([]() { abort(); }, &seccomp_fork);
699 FinishCrasher();
700
701 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
702 AssertDeath(SIGABRT);
703}
704
568TEST_F(CrasherTest, competing_tracer) { 705TEST_F(CrasherTest, competing_tracer) {
569 int intercept_result; 706 int intercept_result;
570 unique_fd output_fd; 707 unique_fd output_fd;