diff options
author | Peter Collingbourne <pcc@google.com> | 2021-01-06 21:02:19 -0800 |
---|---|---|
committer | Peter Collingbourne <pcc@google.com> | 2021-02-12 12:30:52 -0800 |
commit | bb4b49c63c64a622d1b4bc6df00c53a93b3da97d (patch) | |
tree | dcc9ca1dbafc17f287b394c51a0026c48be2f7d7 /debuggerd | |
parent | 7b204ac4cad6531e9d95fa25f787c01e889dd7af (diff) |
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
Diffstat (limited to 'debuggerd')
-rw-r--r-- | debuggerd/crash_dump.cpp | 1 | ||||
-rw-r--r-- | debuggerd/debuggerd_test.cpp | 35 | ||||
-rw-r--r-- | debuggerd/include/debuggerd/handler.h | 1 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/include/libdebuggerd/types.h | 1 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/scudo.cpp | 6 | ||||
-rw-r--r-- | debuggerd/protocol.h | 1 |
6 files changed, 29 insertions, 16 deletions
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 68a43cffb..c8612bfeb 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -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: diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index b9d66063e..abce0569f 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -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)"); diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h index 254ed4f7b..bc08327a1 100644 --- a/debuggerd/include/debuggerd/handler.h +++ b/debuggerd/include/debuggerd/handler.h @@ -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. diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h index d5b07355f..dcb52f92a 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h @@ -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; diff --git a/debuggerd/libdebuggerd/scudo.cpp b/debuggerd/libdebuggerd/scudo.cpp index 141c3bd18..1c3437fde 100644 --- a/debuggerd/libdebuggerd/scudo.cpp +++ b/debuggerd/libdebuggerd/scudo.cpp @@ -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 { diff --git a/debuggerd/protocol.h b/debuggerd/protocol.h index 53a76ea71..f33b2f0c9 100644 --- a/debuggerd/protocol.h +++ b/debuggerd/protocol.h @@ -97,6 +97,7 @@ struct __attribute__((__packed__)) CrashInfoDataDynamic : public CrashInfoDataSt uintptr_t gwp_asan_metadata; uintptr_t scudo_stack_depot; uintptr_t scudo_region_info; + uintptr_t scudo_ring_buffer; }; struct __attribute__((__packed__)) CrashInfo { |