debuggerd: fix several bugs caused by fork/setuid change.
Previously, we weren't PTRACE_ATTACHing to all of the threads of a
process, and we were also trying to do it after forking and dropping
privileges. This patch ensures that all ptrace attaching/detaching
happens in one place, before forking/exiting respectively.
Bug: http://b/26443860
Bug: http://b/26436605
Bug: http://b/26436486
Change-Id: Id94e0c1d9d56c051d0dd281d895aaa3285079198
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index b46f8f4..b6916e5 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -67,8 +67,7 @@
_LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
}
-static void dump_thread(
- log_t* log, pid_t tid, bool attached, bool* detach_failed, int* total_sleep_time_usec) {
+static void dump_thread(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid) {
char path[PATH_MAX];
char threadnamebuf[1024];
char* threadname = NULL;
@@ -88,56 +87,25 @@
_LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
- if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
- _LOG(log, logtype::BACKTRACE, "Could not attach to thread: %s\n", strerror(errno));
- return;
- }
-
- if (!attached && wait_for_sigstop(tid, total_sleep_time_usec, detach_failed) == -1) {
- return;
- }
-
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
if (backtrace->Unwind(0)) {
dump_backtrace_to_log(backtrace.get(), log, " ");
} else {
ALOGE("Unwind failed: tid = %d", tid);
}
-
- if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
- ALOGE("ptrace detach from %d failed: %s\n", tid, strerror(errno));
- *detach_failed = true;
- }
}
-void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
- int* total_sleep_time_usec) {
+void dump_backtrace(int fd, int amfd, BacktraceMap* map, pid_t pid, pid_t tid,
+ const std::set<pid_t>& siblings) {
log_t log;
log.tfd = fd;
log.amfd = amfd;
dump_process_header(&log, pid);
- dump_thread(&log, tid, true, detach_failed, total_sleep_time_usec);
+ dump_thread(&log, map, pid, tid);
- char task_path[64];
- snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
- DIR* d = opendir(task_path);
- if (d != NULL) {
- struct dirent* de = NULL;
- while ((de = readdir(d)) != NULL) {
- if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
- continue;
- }
-
- char* end;
- pid_t new_tid = strtoul(de->d_name, &end, 10);
- if (*end || new_tid == tid) {
- continue;
- }
-
- dump_thread(&log, new_tid, false, detach_failed, total_sleep_time_usec);
- }
- closedir(d);
+ for (pid_t sibling : siblings) {
+ dump_thread(&log, map, pid, sibling);
}
dump_process_footer(&log, pid);