Merge changes from topic 'debuggerd_ambient'

* changes:
  debuggerd_handler: don't use clone(..., SIGCHLD, ...)
  crash_dump: drop capabilities after we ptrace attach.
  crash_dump: use /proc/<pid> fd to check tid process membership.
  debuggerd_handler: raise ambient capset before execing.
  Revert "Give crash_dump CAP_SYS_PTRACE."
This commit is contained in:
Josh Gao 2017-02-06 18:37:54 +00:00 committed by Gerrit Code Review
commit 279cb8b39a
3 changed files with 49 additions and 20 deletions

View File

@ -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.

View File

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

View File

@ -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" },