Merge "debuggerd_handler: set PR_SET_DUMPABLE before running crash_dump."

am: af776fd518

Change-Id: I65a4cf9167f1d2804bd5193f492126e74188b43c
This commit is contained in:
Josh Gao 2017-02-15 07:27:41 +00:00 committed by android-build-merger
commit 877becaf7e
2 changed files with 59 additions and 40 deletions

View File

@ -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";
@ -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;
@ -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";
}
@ -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 {

View File

@ -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 {
@ -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,
@ -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