diff options
-rw-r--r-- | debuggerd/crash_dump.cpp | 48 | ||||
-rw-r--r-- | debuggerd/handler/debuggerd_handler.cpp | 14 | ||||
-rw-r--r-- | libcutils/fs_config.c | 7 |
3 files changed, 49 insertions, 20 deletions
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 58eaed717..ed6d3b7c0 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -18,10 +18,12 @@ #include <dirent.h> #include <fcntl.h> #include <stdlib.h> -#include <syscall.h> +#include <sys/capability.h> +#include <sys/prctl.h> #include <sys/ptrace.h> #include <sys/types.h> #include <sys/un.h> +#include <syscall.h> #include <unistd.h> #include <limits> @@ -51,24 +53,25 @@ using android::base::unique_fd; using android::base::StringPrintf; -static bool pid_contains_tid(pid_t pid, pid_t tid) { - std::string task_path = StringPrintf("/proc/%d/task/%d", pid, tid); - return access(task_path.c_str(), F_OK) == 0; +static bool pid_contains_tid(int pid_proc_fd, pid_t tid) { + struct stat st; + std::string task_path = StringPrintf("task/%d", tid); + return fstatat(pid_proc_fd, task_path.c_str(), &st, 0) == 0; } // Attach to a thread, and verify that it's still a member of the given process -static bool ptrace_seize_thread(pid_t pid, pid_t tid, std::string* error) { +static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error) { if (ptrace(PTRACE_SEIZE, tid, 0, 0) != 0) { *error = StringPrintf("failed to attach to thread %d: %s", tid, strerror(errno)); 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 (!pid_contains_tid(pid_proc_fd, tid)) { if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) { PLOG(FATAL) << "failed to detach from thread " << tid; } - *error = StringPrintf("thread %d is not in process %d", tid, pid); + *error = StringPrintf("thread %d is not in process", tid); return false; } @@ -190,6 +193,24 @@ static void abort_handler(pid_t target, const bool& tombstoned_connected, _exit(1); } +static void drop_capabilities() { + __user_cap_header_struct capheader; + memset(&capheader, 0, sizeof(capheader)); + capheader.version = _LINUX_CAPABILITY_VERSION_3; + capheader.pid = 0; + + __user_cap_data_struct capdata[2]; + memset(&capdata, 0, sizeof(capdata)); + + if (capset(&capheader, &capdata[0]) == -1) { + PLOG(FATAL) << "failed to drop capabilities"; + } + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) { + PLOG(FATAL) << "failed to set PR_SET_NO_NEW_PRIVS"; + } +} + static void check_process(int proc_fd, pid_t expected_pid) { android::procinfo::ProcessInfo proc_info; if (!android::procinfo::GetProcessInfoFromProcPidFd(proc_fd, &proc_info)) { @@ -263,7 +284,7 @@ int main(int argc, char** argv) { check_process(target_proc_fd, target); std::string attach_error; - if (!ptrace_seize_thread(target, main_tid, &attach_error)) { + if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) { LOG(FATAL) << attach_error; } @@ -304,6 +325,7 @@ int main(int argc, char** argv) { } int signo = siginfo.si_signo; + bool fatal_signal = signo != DEBUGGER_SIGNAL; bool backtrace = false; uintptr_t abort_address = 0; @@ -319,17 +341,16 @@ int main(int argc, char** argv) { // Now that we have the signal that kicked things off, attach all of the // sibling threads, and then proceed. - bool fatal_signal = signo != DEBUGGER_SIGNAL; - std::set<pid_t> siblings; std::set<pid_t> attached_siblings; - if (fatal_signal || backtrace) { + { + 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, sibling_tid, &attach_error)) { + if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) { LOG(WARNING) << attach_error; } else { attached_siblings.insert(sibling_tid); @@ -337,6 +358,9 @@ int main(int argc, char** argv) { } } + // 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. diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp index 9469bbdeb..156534e19 100644 --- a/debuggerd/handler/debuggerd_handler.cpp +++ b/debuggerd/handler/debuggerd_handler.cpp @@ -39,6 +39,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/capability.h> #include <sys/mman.h> #include <sys/prctl.h> #include <sys/socket.h> @@ -207,7 +208,7 @@ static int debuggerd_dispatch_pseudothread(void* arg) { } // Don't use fork(2) to avoid calling pthread_atfork handlers. - int forkpid = clone(nullptr, nullptr, SIGCHLD, nullptr); + int forkpid = clone(nullptr, nullptr, 0, nullptr); if (forkpid == -1) { __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to fork in debuggerd signal handler: %s", strerror(errno)); @@ -216,6 +217,11 @@ static int debuggerd_dispatch_pseudothread(void* arg) { close(pipefds[0]); close(pipefds[1]); + // Set all of the ambient capability bits we can, so that crash_dump can ptrace us. + for (unsigned long i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0); ++i) { + prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0); + } + char buf[10]; snprintf(buf, sizeof(buf), "%d", thread_info->crashing_tid); execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, buf, nullptr); @@ -242,10 +248,12 @@ static int debuggerd_dispatch_pseudothread(void* arg) { close(pipefds[0]); // Don't leave a zombie child. - siginfo_t child_siginfo; - if (TEMP_FAILURE_RETRY(waitid(P_PID, forkpid, &child_siginfo, WEXITED)) != 0) { + int status; + if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, __WCLONE)) == -1 && errno != ECHILD) { __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s", strerror(errno)); + } else if (WIFSTOPPED(status) || WIFSIGNALED(status)) { + __libc_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped"); thread_info->crash_dump_started = false; } } diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c index 013999a95..b701bbaae 100644 --- a/libcutils/fs_config.c +++ b/libcutils/fs_config.c @@ -177,11 +177,8 @@ static const struct fs_path_config android_files[] = { CAP_MASK_LONG(CAP_SETPCAP), "system/bin/webview_zygote64" }, - { 00755, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SYS_PTRACE), - "system/bin/crash_dump32" }, - { 00755, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SYS_PTRACE), - "system/bin/crash_dump64" }, - + { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" }, { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/debuggerd" }, { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" }, { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" }, |