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
This commit is contained in:
parent
7b204ac4ca
commit
bb4b49c63c
6 changed files with 29 additions and 16 deletions
|
@ -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:
|
||||
|
|
|
@ -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)");
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue