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

Commit 76e1e30f authored by Josh Gao's avatar Josh Gao
Browse files

Reland protobuf tombstones.

This reverts the following commits:
    e156ede1.
    eda96edd.
    5ec54d1e.
    1e45d3f2.
    a50f61f8.

Test: treehugger
Test: atest -c CtsSeccompHostTestCases:android.seccomp.cts.SeccompHostJUnit4DeviceTest#testAppZygoteSyscalls
Change-Id: Ic2b1f489ac9f1fec7d7a33c845c29891f4306bbd
parent e8cc75f0
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -176,6 +176,8 @@ cc_library_static {
        "libdebuggerd/open_files_list.cpp",
        "libdebuggerd/scudo.cpp",
        "libdebuggerd/tombstone.cpp",
        "libdebuggerd/tombstone_proto.cpp",
        "libdebuggerd/tombstone_proto_to_text.cpp",
        "libdebuggerd/utility.cpp",
    ],

@@ -206,6 +208,8 @@ cc_library_static {
    whole_static_libs: [
        "gwp_asan_crash_handler",
        "libscudo",
        "libtombstone_proto",
        "libprotobuf-cpp-lite",
    ],

    target: {
@@ -228,6 +232,20 @@ cc_library_static {
    },
}

cc_binary {
    name: "pbtombstone",
    defaults: ["debuggerd_defaults"],
    srcs: ["pbtombstone.cpp"],
    static_libs: [
        "libbase",
        "libdebuggerd",
        "liblog",
        "libprotobuf-cpp-lite",
        "libtombstone_proto",
        "libunwindstack",
    ],
}

cc_test {
    name: "debuggerd_test",
    defaults: ["debuggerd_defaults"],
@@ -332,6 +350,9 @@ cc_binary {
        "libtombstoned_client_static",
        "libdebuggerd",
        "libcutils",

        "libtombstone_proto",
        "libprotobuf-cpp-lite",
    ],

    shared_libs: [
+5 −1
Original line number Diff line number Diff line
@@ -24,7 +24,8 @@ enum DebuggerdDumpType : uint8_t {
  kDebuggerdNativeBacktrace,
  kDebuggerdTombstone,
  kDebuggerdJavaBacktrace,
  kDebuggerdAnyIntercept
  kDebuggerdAnyIntercept,
  kDebuggerdTombstoneProto,
};

inline std::ostream& operator<<(std::ostream& stream, const DebuggerdDumpType& rhs) {
@@ -41,6 +42,9 @@ inline std::ostream& operator<<(std::ostream& stream, const DebuggerdDumpType& r
    case kDebuggerdAnyIntercept:
      stream << "kDebuggerdAnyIntercept";
      break;
    case kDebuggerdTombstoneProto:
      stream << "kDebuggerdTombstoneProto";
      break;
    default:
      stream << "[unknown]";
  }
+22 −6
Original line number Diff line number Diff line
@@ -195,6 +195,7 @@ static pid_t g_target_thread = -1;
static bool g_tombstoned_connected = false;
static unique_fd g_tombstoned_socket;
static unique_fd g_output_fd;
static unique_fd g_proto_fd;

static void DefuseSignalHandlers() {
  // Don't try to dump ourselves.
@@ -215,7 +216,7 @@ static void Initialize(char** argv) {
    // If we abort before we get an output fd, contact tombstoned to let any
    // potential listeners know that we failed.
    if (!g_tombstoned_connected) {
      if (!tombstoned_connect(g_target_thread, &g_tombstoned_socket, &g_output_fd,
      if (!tombstoned_connect(g_target_thread, &g_tombstoned_socket, &g_output_fd, &g_proto_fd,
                              kDebuggerdAnyIntercept)) {
        // We failed to connect, not much we can do.
        LOG(ERROR) << "failed to connected to tombstoned to report failure";
@@ -248,10 +249,20 @@ static void ParseArgs(int argc, char** argv, pid_t* pseudothread_tid, DebuggerdD
  }

  int dump_type_int;
  if (!android::base::ParseInt(argv[3], &dump_type_int, 0, 1)) {
  if (!android::base::ParseInt(argv[3], &dump_type_int, 0)) {
    LOG(FATAL) << "invalid requested dump type: " << argv[3];
  }

  *dump_type = static_cast<DebuggerdDumpType>(dump_type_int);
  switch (*dump_type) {
    case kDebuggerdNativeBacktrace:
    case kDebuggerdTombstone:
    case kDebuggerdTombstoneProto:
      break;

    default:
      LOG(FATAL) << "invalid requested dump type: " << dump_type_int;
  }
}

static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo,
@@ -480,6 +491,11 @@ int main(int argc, char** argv) {
      info.process_name = process_name;
      info.thread_name = get_thread_name(thread);

      unique_fd attr_fd(openat(target_proc_fd, "attr/current", O_RDONLY | O_CLOEXEC));
      if (!android::base::ReadFdToString(attr_fd, &info.selinux_label)) {
        PLOG(WARNING) << "failed to read selinux label";
      }

      if (!ptrace_interrupt(thread, &info.signo)) {
        PLOG(WARNING) << "failed to ptrace interrupt thread " << thread;
        ptrace(PTRACE_DETACH, thread, 0, 0);
@@ -558,8 +574,8 @@ int main(int argc, char** argv) {
  {
    ATRACE_NAME("tombstoned_connect");
    LOG(INFO) << "obtaining output fd from tombstoned, type: " << dump_type;
    g_tombstoned_connected =
        tombstoned_connect(g_target_thread, &g_tombstoned_socket, &g_output_fd, dump_type);
    g_tombstoned_connected = tombstoned_connect(g_target_thread, &g_tombstoned_socket, &g_output_fd,
                                                &g_proto_fd, dump_type);
  }

  if (g_tombstoned_connected) {
@@ -612,8 +628,8 @@ int main(int argc, char** argv) {

    {
      ATRACE_NAME("engrave_tombstone");
      engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread, process_info,
                        &open_files, &amfd_data);
      engrave_tombstone(std::move(g_output_fd), std::move(g_proto_fd), &unwinder, thread_info,
                        g_target_thread, process_info, &open_files, &amfd_data);
    }
  }

+69 −2
Original line number Diff line number Diff line
@@ -1309,11 +1309,11 @@ TEST(tombstoned, java_trace_intercept_smoke) {
  tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
  ASSERT_EQ(InterceptStatus::kRegistered, status);

  // First connect to tombstoned requesting a native backtrace. This
  // First connect to tombstoned requesting a native tombstone. This
  // should result in a "regular" FD and not the installed intercept.
  const char native[] = "native";
  unique_fd tombstoned_socket, input_fd;
  ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdNativeBacktrace));
  ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
  ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
  tombstoned_notify_completion(tombstoned_socket.get());

@@ -1425,3 +1425,70 @@ TEST_F(CrasherTest, stack_overflow) {
  ConsumeFd(std::move(output_fd), &result);
  ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
}

TEST(tombstoned, proto) {
  const pid_t self = getpid();
  unique_fd tombstoned_socket, text_fd, proto_fd;
  ASSERT_TRUE(
      tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));

  tombstoned_notify_completion(tombstoned_socket.get());

  ASSERT_NE(-1, text_fd.get());
  ASSERT_NE(-1, proto_fd.get());

  struct stat text_st;
  ASSERT_EQ(0, fstat(text_fd.get(), &text_st));

  // Give tombstoned some time to link the files into place.
  std::this_thread::sleep_for(100ms);

  // Find the tombstone.
  std::optional<int> tombstone_index;
  for (int i = 0; i < 50; ++i) {
    std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);

    struct stat st;
    if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
      continue;
    }

    if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
      tombstone_index = i;
      break;
    }
  }

  ASSERT_TRUE(tombstone_index);
  std::string proto_path =
      android::base::StringPrintf("/data/tombstones/tombstone_%02d.pb", *tombstone_index);

  struct stat proto_fd_st;
  struct stat proto_file_st;
  ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
  ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));

  ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
  ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
}

TEST(tombstoned, proto_intercept) {
  const pid_t self = getpid();
  unique_fd intercept_fd, output_fd;
  InterceptStatus status;

  tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
  ASSERT_EQ(InterceptStatus::kRegistered, status);

  unique_fd tombstoned_socket, text_fd, proto_fd;
  ASSERT_TRUE(
      tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
  ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
  tombstoned_notify_completion(tombstoned_socket.get());

  text_fd.reset();

  std::string output;
  ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
  ASSERT_EQ("foo", output);
}
+10 −9
Original line number Diff line number Diff line
@@ -92,15 +92,15 @@ static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) {
  __linker_disable_fallback_allocator();
}

static void debuggerd_fallback_tombstone(int output_fd, ucontext_t* ucontext, siginfo_t* siginfo,
                                         void* abort_message) {
static void debuggerd_fallback_tombstone(int output_fd, int proto_fd, ucontext_t* ucontext,
                                         siginfo_t* siginfo, void* abort_message) {
  if (!__linker_enable_fallback_allocator()) {
    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "fallback allocator already in use");
    return;
  }

  engrave_tombstone_ucontext(output_fd, reinterpret_cast<uintptr_t>(abort_message), siginfo,
                             ucontext);
  engrave_tombstone_ucontext(output_fd, proto_fd, reinterpret_cast<uintptr_t>(abort_message),
                             siginfo, ucontext);
  __linker_disable_fallback_allocator();
}

@@ -232,7 +232,8 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {

  // Fetch output fd from tombstoned.
  unique_fd tombstone_socket, output_fd;
  if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd, kDebuggerdNativeBacktrace)) {
  if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd, nullptr,
                          kDebuggerdNativeBacktrace)) {
    async_safe_format_log(ANDROID_LOG_ERROR, "libc",
                          "missing crash_dump_fallback() in selinux policy?");
    goto exit;
@@ -325,10 +326,10 @@ static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_mes
    _exit(1);
  }

  unique_fd tombstone_socket, output_fd;
  bool tombstoned_connected =
      tombstoned_connect(getpid(), &tombstone_socket, &output_fd, kDebuggerdTombstone);
  debuggerd_fallback_tombstone(output_fd.get(), ucontext, info, abort_message);
  unique_fd tombstone_socket, output_fd, proto_fd;
  bool tombstoned_connected = tombstoned_connect(getpid(), &tombstone_socket, &output_fd, &proto_fd,
                                                 kDebuggerdTombstoneProto);
  debuggerd_fallback_tombstone(output_fd.get(), proto_fd.get(), ucontext, info, abort_message);
  if (tombstoned_connected) {
    tombstoned_notify_completion(tombstone_socket.get());
  }
Loading