DO NOT MERGE: debuggerd: verify that traced threads belong to the right process.
Fix two races in debuggerd's PTRACE_ATTACH logic:
1. The target thread in a crash dump request could exit between the
/proc/<pid>/task/<tid> check and the PTRACE_ATTACH.
2. Sibling threads could exit between listing /proc/<pid>/task and the
PTRACE_ATTACH.
Backport of NYC change I4dfe1ea30e2c211d2389321bd66e3684dd757591
Bug: http://b/29555636
Change-Id: I6c6efcf82a49bca140d761b2d1de04215ba4d252
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index 9f340a8..236d667 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -20,6 +20,7 @@
#include <errno.h>
#include <signal.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ptrace.h>
@@ -207,3 +208,31 @@
_LOG(log, logtype::MEMORY, "%s %s\n", logline.c_str(), ascii.c_str());
}
}
+
+bool pid_contains_tid(pid_t pid, pid_t tid) {
+ char task_path[PATH_MAX];
+ if (snprintf(task_path, PATH_MAX, "/proc/%d/task/%d", pid, tid) >= PATH_MAX) {
+ ALOGE("debuggerd: task path overflow (pid = %d, tid = %d)\n", pid, tid);
+ exit(1);
+ }
+
+ return access(task_path, F_OK) == 0;
+}
+
+// Attach to a thread, and verify that it's still a member of the given process
+bool ptrace_attach_thread(pid_t pid, pid_t tid) {
+ if (ptrace(PTRACE_ATTACH, tid, 0, 0) != 0) {
+ return false;
+ }
+
+ // Make sure that the task we attached to is actually part of the pid we're dumping.
+ if (!pid_contains_tid(pid, tid)) {
+ if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
+ ALOGE("debuggerd: failed to detach from thread '%d'", tid);
+ exit(1);
+ }
+ return false;
+ }
+
+ return true;
+}