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

Commit bb4b49c6 authored by Peter Collingbourne's avatar Peter Collingbourne
Browse files

Teach debuggerd to pass the secondary ring buffer to __scudo_get_error_info().

With this change we can report memory errors involving secondary
allocations. Update the existing crasher tests to also test
UAF/overflow/underflow on allocations with sizes sufficient to trigger
the secondary allocator.

Bug: 135772972
Change-Id: Ic8925c1f18621a8f272e26d5630e5d11d6d34d38
parent 7b204ac4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -303,6 +303,7 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo,
      process_info->gwp_asan_metadata = crash_info->data.d.gwp_asan_metadata;
      process_info->scudo_stack_depot = crash_info->data.d.scudo_stack_depot;
      process_info->scudo_region_info = crash_info->data.d.scudo_region_info;
      process_info->scudo_ring_buffer = crash_info->data.d.scudo_ring_buffer;
      FALLTHROUGH_INTENDED;
    case 1:
    case 2:
+21 −14
Original line number Diff line number Diff line
@@ -391,7 +391,11 @@ static void SetTagCheckingLevelSync() {
}
#endif

TEST_F(CrasherTest, mte_uaf) {
struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};

INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(16, 131072));

TEST_P(SizeParamCrasherTest, mte_uaf) {
#if defined(__aarch64__)
  if (!mte_supported()) {
    GTEST_SKIP() << "Requires MTE";
@@ -399,9 +403,9 @@ TEST_F(CrasherTest, mte_uaf) {

  int intercept_result;
  unique_fd output_fd;
  StartProcess([]() {
  StartProcess([&]() {
    SetTagCheckingLevelSync();
    volatile int* p = (volatile int*)malloc(16);
    volatile int* p = (volatile int*)malloc(GetParam());
    free((void *)p);
    p[0] = 42;
  });
@@ -416,8 +420,9 @@ TEST_F(CrasherTest, mte_uaf) {
  std::string result;
  ConsumeFd(std::move(output_fd), &result);

  ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
  ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a 16-byte allocation.*
  ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
  ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
                           std::to_string(GetParam()) + R"(-byte allocation.*

allocated by thread .*
      #00 pc)");
@@ -428,7 +433,7 @@ allocated by thread .*
#endif
}

TEST_F(CrasherTest, mte_overflow) {
TEST_P(SizeParamCrasherTest, mte_overflow) {
#if defined(__aarch64__)
  if (!mte_supported()) {
    GTEST_SKIP() << "Requires MTE";
@@ -436,10 +441,10 @@ TEST_F(CrasherTest, mte_overflow) {

  int intercept_result;
  unique_fd output_fd;
  StartProcess([]() {
  StartProcess([&]() {
    SetTagCheckingLevelSync();
    volatile int* p = (volatile int*)malloc(16);
    p[4] = 42;
    volatile char* p = (volatile char*)malloc(GetParam());
    p[GetParam()] = 42;
  });

  StartIntercept(&output_fd);
@@ -453,7 +458,8 @@ TEST_F(CrasherTest, mte_overflow) {
  ConsumeFd(std::move(output_fd), &result);

  ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
  ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation.*
  ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
                           std::to_string(GetParam()) + R"(-byte allocation.*

allocated by thread .*
      #00 pc)");
@@ -462,7 +468,7 @@ allocated by thread .*
#endif
}

TEST_F(CrasherTest, mte_underflow) {
TEST_P(SizeParamCrasherTest, mte_underflow) {
#if defined(__aarch64__)
  if (!mte_supported()) {
    GTEST_SKIP() << "Requires MTE";
@@ -470,9 +476,9 @@ TEST_F(CrasherTest, mte_underflow) {

  int intercept_result;
  unique_fd output_fd;
  StartProcess([]() {
  StartProcess([&]() {
    SetTagCheckingLevelSync();
    volatile int* p = (volatile int*)malloc(16);
    volatile int* p = (volatile int*)malloc(GetParam());
    p[-1] = 42;
  });

@@ -487,7 +493,8 @@ TEST_F(CrasherTest, mte_underflow) {
  ConsumeFd(std::move(output_fd), &result);

  ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
  ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a 16-byte allocation.*
  ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
                           std::to_string(GetParam()) + R"(-byte allocation.*

allocated by thread .*
      #00 pc)");
+1 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ struct debugger_process_info {
  const gwp_asan::AllocationMetadata* gwp_asan_metadata;
  const char* scudo_stack_depot;
  const char* scudo_region_info;
  const char* scudo_ring_buffer;
};

// These callbacks are called in a signal handler, and thus must be async signal safe.
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ struct ProcessInfo {
  uintptr_t gwp_asan_metadata = 0;
  uintptr_t scudo_stack_depot = 0;
  uintptr_t scudo_region_info = 0;
  uintptr_t scudo_ring_buffer = 0;

  bool has_fault_address = false;
  uintptr_t untagged_fault_address = 0;
+4 −2
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@ ScudoCrashData::ScudoCrashData(unwindstack::Memory* process_memory,
                                       __scudo_get_stack_depot_size());
  auto region_info = AllocAndReadFully(process_memory, process_info.scudo_region_info,
                                       __scudo_get_region_info_size());
  auto ring_buffer = AllocAndReadFully(process_memory, process_info.scudo_ring_buffer,
                                       __scudo_get_ring_buffer_size());

  untagged_fault_addr_ = process_info.untagged_fault_address;
  uintptr_t fault_page = untagged_fault_addr_ & ~(PAGE_SIZE - 1);
@@ -68,8 +70,8 @@ ScudoCrashData::ScudoCrashData(unwindstack::Memory* process_memory,
  }

  __scudo_get_error_info(&error_info_, process_info.maybe_tagged_fault_address, stack_depot.get(),
                         region_info.get(), memory.get(), memory_tags.get(), memory_begin,
                         memory_end - memory_begin);
                         region_info.get(), ring_buffer.get(), memory.get(), memory_tags.get(),
                         memory_begin, memory_end - memory_begin);
}

bool ScudoCrashData::CrashIsMine() const {
Loading