diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 34ad7de2e..35139801f 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -79,9 +79,27 @@ static bool pid_contains_tid(int pid_proc_fd, pid_t tid) { return fstatat(pid_proc_fd, task_path.c_str(), &st, 0) == 0; } +static pid_t get_tracer(pid_t tracee) { + // Check to see if the thread is being ptraced by another process. + android::procinfo::ProcessInfo process_info; + if (android::procinfo::GetProcessInfo(tracee, &process_info)) { + return process_info.tracer; + } + return -1; +} + // Attach to a thread, and verify that it's still a member of the given process static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error) { if (ptrace(PTRACE_SEIZE, tid, 0, 0) != 0) { + if (errno == EPERM) { + pid_t tracer = get_tracer(tid); + if (tracer != -1) { + *error = StringPrintf("failed to attach to thread %d, already traced by %d (%s)", tid, + tracer, get_process_name(tracer).c_str()); + return false; + } + } + *error = StringPrintf("failed to attach to thread %d: %s", tid, strerror(errno)); return false; } diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index b51fc665e..dbf81a4ee 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -16,10 +16,11 @@ #include #include -#include #include #include +#include #include +#include #include #include @@ -569,6 +570,40 @@ TEST_F(CrasherTest, fake_pid) { ASSERT_BACKTRACE_FRAME(result, "tgkill"); } +TEST_F(CrasherTest, competing_tracer) { + int intercept_result; + unique_fd output_fd; + StartProcess([]() { + while (true) { + } + }); + + StartIntercept(&output_fd); + FinishCrasher(); + + ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0)); + ASSERT_EQ(0, kill(crasher_pid, SIGABRT)); + + int status; + ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0)); + ASSERT_TRUE(WIFSTOPPED(status)); + ASSERT_EQ(SIGABRT, WSTOPSIG(status)); + + ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT)); + FinishIntercept(&intercept_result); + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + std::string regex = R"(failed to attach to thread \d+, already traced by )"; + regex += std::to_string(gettid()); + regex += R"( \(.+debuggerd_test)"; + ASSERT_MATCH(result, regex.c_str()); + + ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT)); + AssertDeath(SIGABRT); +} + TEST(crash_dump, zombie) { pid_t forkpid = fork();