Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 279cb8b3 authored by Josh Gao's avatar Josh Gao Committed by Gerrit Code Review
Browse files

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."
parents 564aeca9 b3ee52e4
Loading
Loading
Loading
Loading
+36 −12
Original line number Diff line number Diff line
@@ -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.
+11 −3
Original line number Diff line number Diff line
@@ -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;
    }
  }
+2 −5
Original line number Diff line number Diff line
@@ -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" },