Loading debuggerd/crash_dump.cpp +43 −37 Original line number Diff line number Diff line Loading @@ -238,11 +238,12 @@ int main(int argc, char** argv) { action.sa_handler = signal_handler; debuggerd_register_handlers(&action); if (argc != 2) { if (argc != 3) { return 1; } pid_t main_tid; pid_t pseudothread_tid; if (target == 1) { LOG(FATAL) << "target died before we could attach"; Loading @@ -252,6 +253,10 @@ int main(int argc, char** argv) { LOG(FATAL) << "invalid main tid: " << argv[1]; } if (!android::base::ParseInt(argv[2], &pseudothread_tid, 1, std::numeric_limits<pid_t>::max())) { LOG(FATAL) << "invalid pseudothread tid: " << argv[1]; } android::procinfo::ProcessInfo target_info; if (!android::procinfo::GetProcessInfo(main_tid, &target_info)) { LOG(FATAL) << "failed to fetch process info for target " << main_tid; Loading Loading @@ -284,16 +289,53 @@ int main(int argc, char** argv) { check_process(target_proc_fd, target); std::string attach_error; // Seize the main thread. if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) { LOG(FATAL) << attach_error; } // Seize the siblings. std::set<pid_t> attached_siblings; { std::set<pid_t> siblings; if (!android::procinfo::GetProcessTids(target, &siblings)) { PLOG(FATAL) << "failed to get process siblings"; } // but not the already attached main thread. siblings.erase(main_tid); // or the handler pseudothread. siblings.erase(pseudothread_tid); for (pid_t sibling_tid : siblings) { if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) { LOG(WARNING) << attach_error; } else { attached_siblings.insert(sibling_tid); } } } // Collect the backtrace map and open files, while the process still has PR_GET_DUMPABLE=1 std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid)); if (!backtrace_map) { LOG(FATAL) << "failed to create backtrace map"; } // Collect the list of open files. OpenFilesList open_files; populate_open_files_list(target, &open_files); // Drop our capabilities now that we've attached to the threads we care about. drop_capabilities(); check_process(target_proc_fd, target); LOG(INFO) << "obtaining output fd from tombstoned"; tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd); // Write a '\1' to stdout to tell the crashing process to resume. // It also restores the value of PR_SET_DUMPABLE at this point. if (TEMP_FAILURE_RETRY(write(STDOUT_FILENO, "\1", 1)) == -1) { PLOG(ERROR) << "failed to communicate to target process"; } Loading Loading @@ -339,45 +381,9 @@ int main(int argc, char** argv) { abort_address = reinterpret_cast<uintptr_t>(siginfo.si_value.sival_ptr); } // Now that we have the signal that kicked things off, attach all of the // sibling threads, and then proceed. std::set<pid_t> attached_siblings; { std::set<pid_t> siblings; if (!android::procinfo::GetProcessTids(target, &siblings)) { PLOG(FATAL) << "failed to get process siblings"; } siblings.erase(main_tid); for (pid_t sibling_tid : siblings) { if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) { LOG(WARNING) << attach_error; } else { attached_siblings.insert(sibling_tid); } } } std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid)); if (!backtrace_map) { LOG(FATAL) << "failed to create backtrace map"; } // Collect the list of open files. OpenFilesList open_files; if (!backtrace) { populate_open_files_list(target, &open_files); } // Drop our capabilities now that we've attached to the threads we care about. drop_capabilities(); check_process(target_proc_fd, target); // TODO: Use seccomp to lock ourselves down. std::string amfd_data; if (backtrace) { dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, attached_siblings, 0); } else { Loading debuggerd/handler/debuggerd_handler.cpp +16 −3 Original line number Diff line number Diff line Loading @@ -254,9 +254,11 @@ static int debuggerd_dispatch_pseudothread(void* arg) { raise_caps(); char buf[10]; snprintf(buf, sizeof(buf), "%d", thread_info->crashing_tid); execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, buf, nullptr); char main_tid[10]; char pseudothread_tid[10]; snprintf(main_tid, sizeof(main_tid), "%d", thread_info->crashing_tid); snprintf(pseudothread_tid, sizeof(pseudothread_tid), "%d", thread_info->pseudothread_tid); execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, nullptr); fatal_errno("exec failed"); } else { Loading Loading @@ -381,6 +383,12 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) .info = info }; // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us. int orig_dumpable = prctl(PR_GET_DUMPABLE); if (prctl(PR_SET_DUMPABLE, 1) != 0) { fatal_errno("failed to set dumpable"); } // Essentially pthread_create without CLONE_FILES (see debuggerd_dispatch_pseudothread). pid_t child_pid = clone(debuggerd_dispatch_pseudothread, pseudothread_stack, Loading @@ -396,6 +404,11 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) // and then wait for it to finish. __futex_wait(&thread_info.pseudothread_tid, child_pid, nullptr); // Restore PR_SET_DUMPABLE to its original value. if (prctl(PR_SET_DUMPABLE, orig_dumpable) != 0) { fatal_errno("failed to restore dumpable"); } // Signals can either be fatal or nonfatal. // For fatal signals, crash_dump will PTRACE_CONT us with the signal we // crashed with, so that processes using waitpid on us will see that we Loading Loading
debuggerd/crash_dump.cpp +43 −37 Original line number Diff line number Diff line Loading @@ -238,11 +238,12 @@ int main(int argc, char** argv) { action.sa_handler = signal_handler; debuggerd_register_handlers(&action); if (argc != 2) { if (argc != 3) { return 1; } pid_t main_tid; pid_t pseudothread_tid; if (target == 1) { LOG(FATAL) << "target died before we could attach"; Loading @@ -252,6 +253,10 @@ int main(int argc, char** argv) { LOG(FATAL) << "invalid main tid: " << argv[1]; } if (!android::base::ParseInt(argv[2], &pseudothread_tid, 1, std::numeric_limits<pid_t>::max())) { LOG(FATAL) << "invalid pseudothread tid: " << argv[1]; } android::procinfo::ProcessInfo target_info; if (!android::procinfo::GetProcessInfo(main_tid, &target_info)) { LOG(FATAL) << "failed to fetch process info for target " << main_tid; Loading Loading @@ -284,16 +289,53 @@ int main(int argc, char** argv) { check_process(target_proc_fd, target); std::string attach_error; // Seize the main thread. if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) { LOG(FATAL) << attach_error; } // Seize the siblings. std::set<pid_t> attached_siblings; { std::set<pid_t> siblings; if (!android::procinfo::GetProcessTids(target, &siblings)) { PLOG(FATAL) << "failed to get process siblings"; } // but not the already attached main thread. siblings.erase(main_tid); // or the handler pseudothread. siblings.erase(pseudothread_tid); for (pid_t sibling_tid : siblings) { if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) { LOG(WARNING) << attach_error; } else { attached_siblings.insert(sibling_tid); } } } // Collect the backtrace map and open files, while the process still has PR_GET_DUMPABLE=1 std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid)); if (!backtrace_map) { LOG(FATAL) << "failed to create backtrace map"; } // Collect the list of open files. OpenFilesList open_files; populate_open_files_list(target, &open_files); // Drop our capabilities now that we've attached to the threads we care about. drop_capabilities(); check_process(target_proc_fd, target); LOG(INFO) << "obtaining output fd from tombstoned"; tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd); // Write a '\1' to stdout to tell the crashing process to resume. // It also restores the value of PR_SET_DUMPABLE at this point. if (TEMP_FAILURE_RETRY(write(STDOUT_FILENO, "\1", 1)) == -1) { PLOG(ERROR) << "failed to communicate to target process"; } Loading Loading @@ -339,45 +381,9 @@ int main(int argc, char** argv) { abort_address = reinterpret_cast<uintptr_t>(siginfo.si_value.sival_ptr); } // Now that we have the signal that kicked things off, attach all of the // sibling threads, and then proceed. std::set<pid_t> attached_siblings; { std::set<pid_t> siblings; if (!android::procinfo::GetProcessTids(target, &siblings)) { PLOG(FATAL) << "failed to get process siblings"; } siblings.erase(main_tid); for (pid_t sibling_tid : siblings) { if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) { LOG(WARNING) << attach_error; } else { attached_siblings.insert(sibling_tid); } } } std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid)); if (!backtrace_map) { LOG(FATAL) << "failed to create backtrace map"; } // Collect the list of open files. OpenFilesList open_files; if (!backtrace) { populate_open_files_list(target, &open_files); } // Drop our capabilities now that we've attached to the threads we care about. drop_capabilities(); check_process(target_proc_fd, target); // TODO: Use seccomp to lock ourselves down. std::string amfd_data; if (backtrace) { dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, attached_siblings, 0); } else { Loading
debuggerd/handler/debuggerd_handler.cpp +16 −3 Original line number Diff line number Diff line Loading @@ -254,9 +254,11 @@ static int debuggerd_dispatch_pseudothread(void* arg) { raise_caps(); char buf[10]; snprintf(buf, sizeof(buf), "%d", thread_info->crashing_tid); execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, buf, nullptr); char main_tid[10]; char pseudothread_tid[10]; snprintf(main_tid, sizeof(main_tid), "%d", thread_info->crashing_tid); snprintf(pseudothread_tid, sizeof(pseudothread_tid), "%d", thread_info->pseudothread_tid); execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, nullptr); fatal_errno("exec failed"); } else { Loading Loading @@ -381,6 +383,12 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) .info = info }; // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us. int orig_dumpable = prctl(PR_GET_DUMPABLE); if (prctl(PR_SET_DUMPABLE, 1) != 0) { fatal_errno("failed to set dumpable"); } // Essentially pthread_create without CLONE_FILES (see debuggerd_dispatch_pseudothread). pid_t child_pid = clone(debuggerd_dispatch_pseudothread, pseudothread_stack, Loading @@ -396,6 +404,11 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) // and then wait for it to finish. __futex_wait(&thread_info.pseudothread_tid, child_pid, nullptr); // Restore PR_SET_DUMPABLE to its original value. if (prctl(PR_SET_DUMPABLE, orig_dumpable) != 0) { fatal_errno("failed to restore dumpable"); } // Signals can either be fatal or nonfatal. // For fatal signals, crash_dump will PTRACE_CONT us with the signal we // crashed with, so that processes using waitpid on us will see that we Loading