• R/O
  • HTTP
  • SSH
  • HTTPS

コミット

タグ
未設定

よく使われているワード(クリックで追加)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

system/corennnnn


コミットメタ情報

リビジョン8f7cc0e3872b0ea0e2cb3491b9f75d8186b14cc6 (tree)
日時2016-08-16 03:29:09
作者Josh Gao <jmgao@goog...>
コミッターandroid-build-merger

ログメッセージ

DO NOT MERGE: debuggerd: verify that traced threads belong to the right process.
am: 8d6ca194ee

Change-Id: I1459607b655da6e01bd5d59e31bdb6d79d504431

変更サマリ

差分

--- a/debuggerd/backtrace.c
+++ b/debuggerd/backtrace.c
@@ -62,7 +62,7 @@ static void dump_process_footer(log_t* log, pid_t pid) {
6262 _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
6363 }
6464
65-static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool attached,
65+static void dump_thread(log_t* log, pid_t pid, pid_t tid, ptrace_context_t* context, bool attached,
6666 bool* detach_failed, int* total_sleep_time_usec) {
6767 char path[PATH_MAX];
6868 char threadnamebuf[1024];
@@ -84,7 +84,7 @@ static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool a
8484 _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n",
8585 threadname ? threadname : "<unknown>", tid);
8686
87- if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
87+ if (!attached && !ptrace_attach_thread(pid, tid)) {
8888 _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno));
8989 return;
9090 }
@@ -122,7 +122,7 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
122122
123123 ptrace_context_t* context = load_ptrace_context(tid);
124124 dump_process_header(&log, pid);
125- dump_thread(&log, tid, context, true, detach_failed, total_sleep_time_usec);
125+ dump_thread(&log, pid, tid, context, true, detach_failed, total_sleep_time_usec);
126126
127127 char task_path[64];
128128 snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
@@ -140,7 +140,7 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
140140 continue;
141141 }
142142
143- dump_thread(&log, new_tid, context, false, detach_failed, total_sleep_time_usec);
143+ dump_thread(&log, pid, new_tid, context, false, detach_failed, total_sleep_time_usec);
144144 }
145145 closedir(d);
146146 }
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -233,13 +233,11 @@ static int read_request(int fd, debugger_request_t* out_request) {
233233
234234 if (msg.action == DEBUGGER_ACTION_CRASH) {
235235 /* Ensure that the tid reported by the crashing process is valid. */
236- char buf[64];
237- struct stat s;
238- snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
239- if(stat(buf, &s)) {
240- LOG("tid %d does not exist in pid %d. ignoring debug request\n",
241- out_request->tid, out_request->pid);
242- return -1;
236+ // This check needs to happen again after ptracing the requested thread to prevent a race.
237+ if (!pid_contains_tid(out_request->pid, out_request->tid)) {
238+ XLOG("tid %d does not exist in pid %d. ignoring debug request\n", out_request->tid,
239+ out_request->pid);
240+ return -1;
243241 }
244242 } else if (cr.uid == 0
245243 || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) {
@@ -290,9 +288,32 @@ static void handle_request(int fd) {
290288 * See details in bionic/libc/linker/debugger.c, in function
291289 * debugger_signal_handler().
292290 */
293- if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
291+ if (!ptrace_attach_thread(request.pid, request.tid)) {
294292 LOG("ptrace attach failed: %s\n", strerror(errno));
295293 } else {
294+ // DEBUGGER_ACTION_CRASH requests can come from arbitrary processes and the tid field in
295+ // the request is sent from the other side. If an attacker can cause a process to be
296+ // spawned with the pid of their process, they could trick debuggerd into dumping that
297+ // process by exiting after sending the request. Validate the trusted request.uid/gid
298+ // to defend against this.
299+ if (request.action == DEBUGGER_ACTION_CRASH) {
300+ pid_t pid;
301+ uid_t uid;
302+ gid_t gid;
303+ if (get_process_info(request.tid, &pid, &uid, &gid) != 0) {
304+ XLOG("debuggerd: failed to get process info for tid '%d'", request.tid);
305+ exit(1);
306+ }
307+
308+ if (pid != request.pid || uid != request.uid || gid != request.gid) {
309+ XLOG(
310+ "debuggerd: attached task %d does not match request: "
311+ "expected pid=%d,uid=%d,gid=%d, actual pid=%d,uid=%d,gid=%d",
312+ request.tid, request.pid, request.uid, request.gid, pid, uid, gid);
313+ exit(1);
314+ }
315+ }
316+
296317 bool detach_failed = false;
297318 bool attach_gdb = should_attach_gdb(&request);
298319 if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
--- a/debuggerd/tombstone.c
+++ b/debuggerd/tombstone.c
@@ -459,7 +459,7 @@ static bool dump_sibling_thread_report(const ptrace_context_t* context,
459459 }
460460
461461 /* Skip this thread if cannot ptrace it */
462- if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) {
462+ if (!ptrace_attach_thread(pid, new_tid)) {
463463 continue;
464464 }
465465
--- a/debuggerd/utility.c
+++ b/debuggerd/utility.c
@@ -18,6 +18,7 @@
1818 #include <stddef.h>
1919 #include <stdbool.h>
2020 #include <stdio.h>
21+#include <stdlib.h>
2122 #include <string.h>
2223 #include <errno.h>
2324 #include <unistd.h>
@@ -128,3 +129,31 @@ void wait_for_stop(pid_t tid, int* total_sleep_time_usec) {
128129 *total_sleep_time_usec += sleep_time_usec;
129130 }
130131 }
132+
133+bool pid_contains_tid(pid_t pid, pid_t tid) {
134+ char task_path[PATH_MAX];
135+ if (snprintf(task_path, PATH_MAX, "/proc/%d/task/%d", pid, tid) >= PATH_MAX) {
136+ XLOG("debuggerd: task path overflow (pid = %d, tid = %d)\n", pid, tid);
137+ exit(1);
138+ }
139+
140+ return access(task_path, F_OK) == 0;
141+}
142+
143+// Attach to a thread, and verify that it's still a member of the given process
144+bool ptrace_attach_thread(pid_t pid, pid_t tid) {
145+ if (ptrace(PTRACE_ATTACH, tid, 0, 0) != 0) {
146+ return false;
147+ }
148+
149+ // Make sure that the task we attached to is actually part of the pid we're dumping.
150+ if (!pid_contains_tid(pid, tid)) {
151+ if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
152+ XLOG("debuggerd: failed to detach from thread '%d'", tid);
153+ exit(1);
154+ }
155+ return false;
156+ }
157+
158+ return true;
159+}
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -63,4 +63,9 @@ void _LOG(log_t* log, int scopeFlags, const char *fmt, ...)
6363 int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
6464 void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
6565
66+bool pid_contains_tid(pid_t pid, pid_t tid);
67+
68+// Attach to a thread, and verify that it's still a member of the given process
69+bool ptrace_attach_thread(pid_t pid, pid_t tid);
70+
6671 #endif // _DEBUGGERD_UTILITY_H