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

Commit d81a2fab authored by Josh Gao's avatar Josh Gao Committed by android-build-merger
Browse files

Merge commit 'd3896c10' into nyc-dev-plus-aosp am: e758b2b3

am: e28282c2

Change-Id: I1686bec34d1f7fe407e71a486c70a2dc90660712
parents 2755196c e28282c2
Loading
Loading
Loading
Loading
+75 −9
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@
#include <errno.h>
#include <errno.h>
#include <inttypes.h>
#include <inttypes.h>
#include <pthread.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <signal.h>
#include <stddef.h>
#include <stddef.h>
#include <stdio.h>
#include <stdio.h>
@@ -41,6 +42,7 @@
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/syscall.h>
#include <sys/un.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>
#include <unistd.h>


#include "private/libc_logging.h"
#include "private/libc_logging.h"
@@ -56,6 +58,13 @@


static debuggerd_callbacks_t g_callbacks;
static debuggerd_callbacks_t g_callbacks;


// Don't use __libc_fatal because it exits via abort, which might put us back into a signal handler.
#define fatal(...)                                             \
  do {                                                         \
    __libc_format_log(ANDROID_LOG_FATAL, "libc", __VA_ARGS__); \
    _exit(1);                                                  \
  } while (0)

static int socket_abstract_client(const char* name, int type) {
static int socket_abstract_client(const char* name, int type) {
  sockaddr_un addr;
  sockaddr_un addr;


@@ -188,7 +197,7 @@ static bool have_siginfo(int signum) {
  return result;
  return result;
}
}


static void send_debuggerd_packet() {
static void send_debuggerd_packet(pid_t crashing_tid, pid_t pseudothread_tid) {
  // Mutex to prevent multiple crashing threads from trying to talk
  // Mutex to prevent multiple crashing threads from trying to talk
  // to debuggerd at the same time.
  // to debuggerd at the same time.
  static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
  static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -218,7 +227,8 @@ static void send_debuggerd_packet() {
  // that's actually in our process.
  // that's actually in our process.
  debugger_msg_t msg;
  debugger_msg_t msg;
  msg.action = DEBUGGER_ACTION_CRASH;
  msg.action = DEBUGGER_ACTION_CRASH;
  msg.tid = gettid();
  msg.tid = crashing_tid;
  msg.ignore_tid = pseudothread_tid;
  msg.abort_msg_address = 0;
  msg.abort_msg_address = 0;


  if (g_callbacks.get_abort_message) {
  if (g_callbacks.get_abort_message) {
@@ -229,11 +239,9 @@ static void send_debuggerd_packet() {
  if (ret == sizeof(msg)) {
  if (ret == sizeof(msg)) {
    char debuggerd_ack;
    char debuggerd_ack;
    ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1));
    ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1));
    int saved_errno = errno;
    if (g_callbacks.post_dump) {
    if (g_callbacks.post_dump) {
      g_callbacks.post_dump();
      g_callbacks.post_dump();
    }
    }
    errno = saved_errno;
  } else {
  } else {
    // read or write failed -- broken connection?
    // read or write failed -- broken connection?
    __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s",
    __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s",
@@ -243,6 +251,33 @@ static void send_debuggerd_packet() {
  close(s);
  close(s);
}
}


struct debugger_thread_info {
  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  pid_t crashing_tid;
  pid_t pseudothread_tid;
  int signal_number;
  siginfo_t* info;
};

// Logging and contacting debuggerd requires free file descriptors, which we might not have.
// Work around this by spawning a "thread" that shares its parent's address space, but not its file
// descriptor table, so that we can close random file descriptors without affecting the original
// process. Note that this doesn't go through pthread_create, so TLS is shared with the spawning
// process.
static void* pseudothread_stack;
static int debuggerd_dispatch_pseudothread(void* arg) {
  debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg);

  for (int i = 3; i < 1024; ++i) {
    close(i);
  }

  log_signal_summary(thread_info->signal_number, thread_info->info);
  send_debuggerd_packet(thread_info->crashing_tid, thread_info->pseudothread_tid);
  pthread_mutex_unlock(&thread_info->mutex);
  return 0;
}

/*
/*
 * Catches fatal signals so we can ask debuggerd to ptrace us before
 * Catches fatal signals so we can ask debuggerd to ptrace us before
 * we crash.
 * we crash.
@@ -254,9 +289,25 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*)
    info = nullptr;
    info = nullptr;
  }
  }


  log_signal_summary(signal_number, info);
  debugger_thread_info thread_info = {
    .crashing_tid = gettid(),
    .signal_number = signal_number,
    .info = info
  };

  pthread_mutex_lock(&thread_info.mutex);
  pid_t child_pid = clone(debuggerd_dispatch_pseudothread, pseudothread_stack,
                          CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID,
                          &thread_info, nullptr, nullptr, &thread_info.pseudothread_tid);

  if (child_pid == -1) {
    fatal("failed to spawn debuggerd dispatch thread: %s", strerror(errno));
  }

  // Wait for the child to finish and unlock the mutex.
  // This relies on bionic behavior that isn't guaranteed by the standard.
  pthread_mutex_lock(&thread_info.mutex);


  send_debuggerd_packet();


  // We need to return from the signal handler so that debuggerd can dump the
  // We need to return from the signal handler so that debuggerd can dump the
  // thread that crashed, but returning here does not guarantee that the signal
  // thread that crashed, but returning here does not guarantee that the signal
@@ -281,9 +332,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*)


  int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), signal_number, info);
  int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), signal_number, info);
  if (rc != 0) {
  if (rc != 0) {
    __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to resend signal during crash: %s",
    fatal("failed to resend signal during crash: %s", strerror(errno));
                      strerror(errno));
    _exit(0);
  }
  }
}
}


@@ -292,6 +341,23 @@ void debuggerd_init(debuggerd_callbacks_t* callbacks) {
    g_callbacks = *callbacks;
    g_callbacks = *callbacks;
  }
  }


  void* thread_stack_allocation =
    mmap(nullptr, PAGE_SIZE * 3, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  if (thread_stack_allocation == MAP_FAILED) {
    fatal("failed to allocate debuggerd thread stack");
  }

  char* stack = static_cast<char*>(thread_stack_allocation) + PAGE_SIZE;
  if (mprotect(stack, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
    fatal("failed to mprotect debuggerd thread stack");
  }

  // Stack grows negatively, set it to the last byte in the page...
  stack = (stack + PAGE_SIZE - 1);
  // and align it.
  stack -= 15;
  pseudothread_stack = stack;

  struct sigaction action;
  struct sigaction action;
  memset(&action, 0, sizeof(action));
  memset(&action, 0, sizeof(action));
  sigemptyset(&action.sa_mask);
  sigemptyset(&action.sa_mask);
+10 −1
Original line number Original line Diff line number Diff line
#include <assert.h>
#include <assert.h>
#include <errno.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <pthread.h>
#include <sched.h>
#include <sched.h>
#include <signal.h>
#include <signal.h>
@@ -141,7 +142,13 @@ static int do_action(const char* arg)
{
{
    fprintf(stderr, "%s: init pid=%d tid=%d\n", __progname, getpid(), gettid());
    fprintf(stderr, "%s: init pid=%d tid=%d\n", __progname, getpid(), gettid());


    if (!strncmp(arg, "thread-", strlen("thread-"))) {
    if (!strncmp(arg, "exhaustfd-", strlen("exhaustfd-"))) {
      errno = 0;
      while (errno != EMFILE) {
        open("/dev/null", O_RDONLY);
      }
      return do_action(arg + strlen("exhaustfd-"));
    } else if (!strncmp(arg, "thread-", strlen("thread-"))) {
        return do_action_on_thread(arg + strlen("thread-"));
        return do_action_on_thread(arg + strlen("thread-"));
    } else if (!strcmp(arg, "SIGSEGV-non-null")) {
    } else if (!strcmp(arg, "SIGSEGV-non-null")) {
        sigsegv_non_null();
        sigsegv_non_null();
@@ -208,6 +215,8 @@ static int do_action(const char* arg)
    fprintf(stderr, "  SIGTRAP               cause a SIGTRAP\n");
    fprintf(stderr, "  SIGTRAP               cause a SIGTRAP\n");
    fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
    fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
    fprintf(stderr, "on the process' main thread.\n");
    fprintf(stderr, "on the process' main thread.\n");
    fprintf(stderr, "prefix any of the above with 'exhaustfd-' to exhaust\n");
    fprintf(stderr, "all available file descriptors before crashing.\n");
    return EXIT_SUCCESS;
    return EXIT_SUCCESS;
}
}


+5 −3
Original line number Original line Diff line number Diff line
@@ -69,6 +69,7 @@ struct debugger_request_t {
  debugger_action_t action;
  debugger_action_t action;
  pid_t pid, tid;
  pid_t pid, tid;
  uid_t uid, gid;
  uid_t uid, gid;
  pid_t ignore_tid;
  uintptr_t abort_msg_address;
  uintptr_t abort_msg_address;
};
};


@@ -225,6 +226,7 @@ static int read_request(int fd, debugger_request_t* out_request) {


  out_request->action = static_cast<debugger_action_t>(msg.action);
  out_request->action = static_cast<debugger_action_t>(msg.action);
  out_request->tid = msg.tid;
  out_request->tid = msg.tid;
  out_request->ignore_tid = msg.ignore_tid;
  out_request->pid = cr.pid;
  out_request->pid = cr.pid;
  out_request->uid = cr.uid;
  out_request->uid = cr.uid;
  out_request->gid = cr.gid;
  out_request->gid = cr.gid;
@@ -433,7 +435,7 @@ static bool ptrace_attach_thread(pid_t pid, pid_t tid) {
  return true;
  return true;
}
}


static void ptrace_siblings(pid_t pid, pid_t main_tid, std::set<pid_t>& tids) {
static void ptrace_siblings(pid_t pid, pid_t main_tid, pid_t ignore_tid, std::set<pid_t>& tids) {
  char task_path[PATH_MAX];
  char task_path[PATH_MAX];


  if (snprintf(task_path, PATH_MAX, "/proc/%d/task", pid) >= PATH_MAX) {
  if (snprintf(task_path, PATH_MAX, "/proc/%d/task", pid) >= PATH_MAX) {
@@ -462,7 +464,7 @@ static void ptrace_siblings(pid_t pid, pid_t main_tid, std::set<pid_t>& tids) {
      continue;
      continue;
    }
    }


    if (tid == main_tid) {
    if (tid == main_tid || tid == ignore_tid) {
      continue;
      continue;
    }
    }


@@ -633,7 +635,7 @@ static void worker_process(int fd, debugger_request_t& request) {


  std::set<pid_t> siblings;
  std::set<pid_t> siblings;
  if (!attach_gdb) {
  if (!attach_gdb) {
    ptrace_siblings(request.pid, request.tid, siblings);
    ptrace_siblings(request.pid, request.tid, request.ignore_tid, siblings);
  }
  }


  // Generate the backtrace map before dropping privileges.
  // Generate the backtrace map before dropping privileges.
+1 −0
Original line number Original line Diff line number Diff line
@@ -43,6 +43,7 @@ typedef enum {
typedef struct __attribute__((packed)) {
typedef struct __attribute__((packed)) {
  int32_t action;
  int32_t action;
  pid_t tid;
  pid_t tid;
  pid_t ignore_tid;
  uint64_t abort_msg_address;
  uint64_t abort_msg_address;
} debugger_msg_t;
} debugger_msg_t;