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

Commit 2dd81da3 authored by Mitch Phillips's avatar Mitch Phillips Committed by Gerrit Code Review
Browse files

Merge "[GWP-ASan] Add GWP-ASan information to tombstones."

parents 2bca658a e0b4bb1b
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -171,6 +171,7 @@ cc_library_static {

    srcs: [
        "libdebuggerd/backtrace.cpp",
        "libdebuggerd/gwp_asan.cpp",
        "libdebuggerd/open_files_list.cpp",
        "libdebuggerd/tombstone.cpp",
        "libdebuggerd/utility.cpp",
@@ -181,7 +182,10 @@ cc_library_static {

    // Needed for private/bionic_fdsan.h
    include_dirs: ["bionic/libc"],
    header_libs: ["bionic_libc_platform_headers"],
    header_libs: [
        "bionic_libc_platform_headers",
        "gwp_asan_headers",
    ],

    static_libs: [
        "libdexfile_support_static",  // libunwindstack dependency
@@ -192,6 +196,8 @@ cc_library_static {
        "liblog",
    ],

    whole_static_libs: ["gwp_asan_crash_handler"],

    target: {
        recovery: {
            exclude_static_libs: [
@@ -246,10 +252,12 @@ cc_test {

    static_libs: [
        "libdebuggerd",
        "libgmock",
    ],

    header_libs: [
        "bionic_libc_platform_headers",
        "gwp_asan_headers",
    ],

    local_include_dirs: [
+2 −2
Original line number Diff line number Diff line
@@ -73,8 +73,8 @@ TEST(debuggerd_client, race) {
  unique_fd pipe_read, pipe_write;
  ASSERT_TRUE(Pipe(&pipe_read, &pipe_write));

  // 64 MiB should be enough for everyone.
  constexpr int PIPE_SIZE = 64 * 1024 * 1024;
  // 16 MiB should be enough for everyone.
  constexpr int PIPE_SIZE = 16 * 1024 * 1024;
  ASSERT_EQ(PIPE_SIZE, fcntl(pipe_read.get(), F_SETPIPE_SZ, PIPE_SIZE));

  // Wait for a bit to let the child spawn all of its threads.
+17 −3
Original line number Diff line number Diff line
@@ -255,7 +255,8 @@ static void ParseArgs(int argc, char** argv, pid_t* pseudothread_tid, DebuggerdD

static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo,
                          std::unique_ptr<unwindstack::Regs>* regs, uintptr_t* abort_msg_address,
                          uintptr_t* fdsan_table_address) {
                          uintptr_t* fdsan_table_address, uintptr_t* gwp_asan_state,
                          uintptr_t* gwp_asan_metadata) {
  std::aligned_storage<sizeof(CrashInfo) + 1, alignof(CrashInfo)>::type buf;
  CrashInfo* crash_info = reinterpret_cast<CrashInfo*>(&buf);
  ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &buf, sizeof(buf)));
@@ -272,6 +273,10 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo,
        expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV2);
        break;

      case 3:
        expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV3);
        break;

      default:
        LOG(FATAL) << "unexpected CrashInfo version: " << crash_info->header.version;
        break;
@@ -284,7 +289,13 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo,
  }

  *fdsan_table_address = 0;
  *gwp_asan_state = 0;
  *gwp_asan_metadata = 0;
  switch (crash_info->header.version) {
    case 3:
      *gwp_asan_state = crash_info->data.v3.gwp_asan_state;
      *gwp_asan_metadata = crash_info->data.v3.gwp_asan_metadata;
      FALLTHROUGH_INTENDED;
    case 2:
      *fdsan_table_address = crash_info->data.v2.fdsan_table_address;
      FALLTHROUGH_INTENDED;
@@ -416,6 +427,8 @@ int main(int argc, char** argv) {
  DebuggerdDumpType dump_type;
  uintptr_t abort_msg_address = 0;
  uintptr_t fdsan_table_address = 0;
  uintptr_t gwp_asan_state = 0;
  uintptr_t gwp_asan_metadata = 0;

  Initialize(argv);
  ParseArgs(argc, argv, &pseudothread_tid, &dump_type);
@@ -477,7 +490,7 @@ int main(int argc, char** argv) {
      if (thread == g_target_thread) {
        // Read the thread's registers along with the rest of the crash info out of the pipe.
        ReadCrashInfo(input_pipe, &siginfo, &info.registers, &abort_msg_address,
                      &fdsan_table_address);
                      &fdsan_table_address, &gwp_asan_state, &gwp_asan_metadata);
        info.siginfo = &siginfo;
        info.signo = info.siginfo->si_signo;
      } else {
@@ -592,7 +605,8 @@ int main(int argc, char** argv) {
    {
      ATRACE_NAME("engrave_tombstone");
      engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread,
                        abort_msg_address, &open_files, &amfd_data);
                        abort_msg_address, &open_files, &amfd_data, gwp_asan_state,
                        gwp_asan_metadata);
    }
  }

+19 −4
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
#include <sys/wait.h>
#include <unistd.h>

#include <android-base/macros.h>
#include <android-base/unique_fd.h>
#include <async_safe/log.h>
#include <bionic/reserved_signals.h>
@@ -298,6 +299,8 @@ struct debugger_thread_info {
  void* ucontext;
  uintptr_t abort_msg;
  uintptr_t fdsan_table;
  uintptr_t gwp_asan_state;
  uintptr_t gwp_asan_metadata;
};

// Logging and contacting debuggerd requires free file descriptors, which we might not have.
@@ -342,23 +345,25 @@ static int debuggerd_dispatch_pseudothread(void* arg) {
  }

  // ucontext_t is absurdly large on AArch64, so piece it together manually with writev.
  uint32_t version = 2;
  constexpr size_t expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV2);
  uint32_t version = 3;
  constexpr size_t expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV3);

  errno = 0;
  if (fcntl(output_write.get(), F_SETPIPE_SZ, expected) < static_cast<int>(expected)) {
    fatal_errno("failed to set pipe buffer size");
  }

  struct iovec iovs[5] = {
  struct iovec iovs[] = {
      {.iov_base = &version, .iov_len = sizeof(version)},
      {.iov_base = thread_info->siginfo, .iov_len = sizeof(siginfo_t)},
      {.iov_base = thread_info->ucontext, .iov_len = sizeof(ucontext_t)},
      {.iov_base = &thread_info->abort_msg, .iov_len = sizeof(uintptr_t)},
      {.iov_base = &thread_info->fdsan_table, .iov_len = sizeof(uintptr_t)},
      {.iov_base = &thread_info->gwp_asan_state, .iov_len = sizeof(uintptr_t)},
      {.iov_base = &thread_info->gwp_asan_metadata, .iov_len = sizeof(uintptr_t)},
  };

  ssize_t rc = TEMP_FAILURE_RETRY(writev(output_write.get(), iovs, 5));
  ssize_t rc = TEMP_FAILURE_RETRY(writev(output_write.get(), iovs, arraysize(iovs)));
  if (rc == -1) {
    fatal_errno("failed to write crash info");
  } else if (rc != expected) {
@@ -485,6 +490,8 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c
  }

  void* abort_message = nullptr;
  const gwp_asan::AllocatorState* gwp_asan_state = nullptr;
  const gwp_asan::AllocationMetadata* gwp_asan_metadata = nullptr;
  uintptr_t si_val = reinterpret_cast<uintptr_t>(info->si_ptr);
  if (signal_number == BIONIC_SIGNAL_DEBUGGER) {
    if (info->si_code == SI_QUEUE && info->si_pid == __getpid()) {
@@ -499,6 +506,12 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c
    if (g_callbacks.get_abort_message) {
      abort_message = g_callbacks.get_abort_message();
    }
    if (g_callbacks.get_gwp_asan_state) {
      gwp_asan_state = g_callbacks.get_gwp_asan_state();
    }
    if (g_callbacks.get_gwp_asan_metadata) {
      gwp_asan_metadata = g_callbacks.get_gwp_asan_metadata();
    }
  }

  // If sival_int is ~0, it means that the fallback handler has been called
@@ -532,6 +545,8 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c
      .ucontext = context,
      .abort_msg = reinterpret_cast<uintptr_t>(abort_message),
      .fdsan_table = reinterpret_cast<uintptr_t>(android_fdsan_get_fd_table()),
      .gwp_asan_state = reinterpret_cast<uintptr_t>(gwp_asan_state),
      .gwp_asan_metadata = reinterpret_cast<uintptr_t>(gwp_asan_metadata),
  };

  // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us.
+9 −0
Original line number Diff line number Diff line
@@ -24,11 +24,20 @@

__BEGIN_DECLS

// Forward declare these classes so not everyone has to include GWP-ASan
// headers.
namespace gwp_asan {
struct AllocatorState;
struct AllocationMetadata;
};  // namespace gwp_asan

// These callbacks are called in a signal handler, and thus must be async signal safe.
// If null, the callbacks will not be called.
typedef struct {
  struct abort_msg_t* (*get_abort_message)();
  void (*post_dump)();
  const struct gwp_asan::AllocatorState* (*get_gwp_asan_state)();
  const struct gwp_asan::AllocationMetadata* (*get_gwp_asan_metadata)();
} debuggerd_callbacks_t;

void debuggerd_init(debuggerd_callbacks_t* callbacks);
Loading