Remove dead non-proto tombstone reporting code.

Bug: 197981919
Change-Id: I58a98070198ef0b686229bd54f87b9073df12d66
This commit is contained in:
Peter Collingbourne 2022-03-07 17:01:17 -08:00
parent 0326984c42
commit a6fac881b2
6 changed files with 0 additions and 423 deletions

View file

@ -282,7 +282,6 @@ cc_test {
"libdebuggerd/test/elf_fake.cpp",
"libdebuggerd/test/log_fake.cpp",
"libdebuggerd/test/open_files_list_test.cpp",
"libdebuggerd/test/tombstone_test.cpp",
"libdebuggerd/test/utility_test.cpp",
],

View file

@ -161,112 +161,3 @@ void GwpAsanCrashData::AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinde
set_human_readable_cause(cause, crash_address_);
}
void GwpAsanCrashData::DumpCause(log_t* log) const {
if (!CrashIsMine()) {
ALOGE("Internal Error: DumpCause() on a non-GWP-ASan crash.");
return;
}
if (error_ == gwp_asan::Error::UNKNOWN) {
_LOG(log, logtype::HEADER, "Cause: [GWP-ASan]: Unknown error occurred at 0x%" PRIxPTR ".\n",
crash_address_);
return;
}
if (!responsible_allocation_) {
_LOG(log, logtype::HEADER, "Cause: [GWP-ASan]: %s at 0x%" PRIxPTR ".\n", error_string_,
crash_address_);
return;
}
uintptr_t alloc_address = __gwp_asan_get_allocation_address(responsible_allocation_);
size_t alloc_size = __gwp_asan_get_allocation_size(responsible_allocation_);
uintptr_t diff;
const char* location_str;
if (crash_address_ < alloc_address) {
// Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef.
location_str = "left of";
diff = alloc_address - crash_address_;
} else if (crash_address_ - alloc_address < alloc_size) {
// Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef.
location_str = "into";
diff = crash_address_ - alloc_address;
} else {
// Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef, or
// Invalid Free, 47 bytes right of a 41-byte allocation at 0xdeadbeef.
location_str = "right of";
diff = crash_address_ - alloc_address;
if (error_ == gwp_asan::Error::BUFFER_OVERFLOW) {
diff -= alloc_size;
}
}
// Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'.
const char* byte_suffix = "s";
if (diff == 1) {
byte_suffix = "";
}
_LOG(log, logtype::HEADER,
"Cause: [GWP-ASan]: %s, %" PRIuPTR " byte%s %s a %zu-byte allocation at 0x%" PRIxPTR "\n",
error_string_, diff, byte_suffix, location_str, alloc_size, alloc_address);
}
bool GwpAsanCrashData::HasDeallocationTrace() const {
assert(CrashIsMine() && "HasDeallocationTrace(): Crash is not mine!");
if (!responsible_allocation_ || !__gwp_asan_is_deallocated(responsible_allocation_)) {
return false;
}
return true;
}
void GwpAsanCrashData::DumpDeallocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const {
assert(HasDeallocationTrace() && "DumpDeallocationTrace(): No dealloc trace!");
uint64_t thread_id = __gwp_asan_get_deallocation_thread_id(responsible_allocation_);
std::unique_ptr<uintptr_t[]> frames(new uintptr_t[kMaxTraceLength]);
size_t num_frames =
__gwp_asan_get_deallocation_trace(responsible_allocation_, frames.get(), kMaxTraceLength);
if (thread_id == gwp_asan::kInvalidThreadID) {
_LOG(log, logtype::BACKTRACE, "\ndeallocated by thread <unknown>:\n");
} else {
_LOG(log, logtype::BACKTRACE, "\ndeallocated by thread %" PRIu64 ":\n", thread_id);
}
unwinder->SetDisplayBuildID(true);
for (size_t i = 0; i < num_frames; ++i) {
unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(frames[i]);
frame_data.num = i;
_LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
}
}
bool GwpAsanCrashData::HasAllocationTrace() const {
assert(CrashIsMine() && "HasAllocationTrace(): Crash is not mine!");
return responsible_allocation_ != nullptr;
}
void GwpAsanCrashData::DumpAllocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const {
assert(HasAllocationTrace() && "DumpAllocationTrace(): No dealloc trace!");
uint64_t thread_id = __gwp_asan_get_allocation_thread_id(responsible_allocation_);
std::unique_ptr<uintptr_t[]> frames(new uintptr_t[kMaxTraceLength]);
size_t num_frames =
__gwp_asan_get_allocation_trace(responsible_allocation_, frames.get(), kMaxTraceLength);
if (thread_id == gwp_asan::kInvalidThreadID) {
_LOG(log, logtype::BACKTRACE, "\nallocated by thread <unknown>:\n");
} else {
_LOG(log, logtype::BACKTRACE, "\nallocated by thread %" PRIu64 ":\n", thread_id);
}
unwinder->SetDisplayBuildID(true);
for (size_t i = 0; i < num_frames; ++i) {
unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(frames[i]);
frame_data.num = i;
_LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
}
}

View file

@ -52,26 +52,6 @@ class GwpAsanCrashData {
// allocator crash state.
uintptr_t GetFaultAddress() const;
// Dump the GWP-ASan stringified cause of this crash. May only be called if
// CrashIsMine() returns true.
void DumpCause(log_t* log) const;
// Returns whether this crash has a deallocation trace. May only be called if
// CrashIsMine() returns true.
bool HasDeallocationTrace() const;
// Dump the GWP-ASan deallocation trace for this crash. May only be called if
// HasDeallocationTrace() returns true.
void DumpDeallocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const;
// Returns whether this crash has a allocation trace. May only be called if
// CrashIsMine() returns true.
bool HasAllocationTrace() const;
// Dump the GWP-ASan allocation trace for this crash. May only be called if
// HasAllocationTrace() returns true.
void DumpAllocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const;
void AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder* unwinder) const;
protected:

View file

@ -34,16 +34,12 @@ class ScudoCrashData {
bool CrashIsMine() const;
void DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const;
void AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder* unwinder) const;
private:
scudo_error_info error_info_ = {};
uintptr_t untagged_fault_addr_;
void DumpReport(const scudo_error_report* report, log_t* log,
unwindstack::Unwinder* unwinder) const;
void FillInCause(Cause* cause, const scudo_error_report* report,
unwindstack::Unwinder* unwinder) const;
};

View file

@ -130,87 +130,3 @@ void ScudoCrashData::AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder*
FillInCause(tombstone->add_causes(), &error_info_.reports[report_num++], unwinder);
}
}
void ScudoCrashData::DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const {
if (error_info_.reports[1].error_type != UNKNOWN) {
_LOG(log, logtype::HEADER,
"\nNote: multiple potential causes for this crash were detected, listing them in "
"decreasing order of likelihood.\n");
}
size_t report_num = 0;
while (report_num < sizeof(error_info_.reports) / sizeof(error_info_.reports[0]) &&
error_info_.reports[report_num].error_type != UNKNOWN) {
DumpReport(&error_info_.reports[report_num++], log, unwinder);
}
}
void ScudoCrashData::DumpReport(const scudo_error_report* report, log_t* log,
unwindstack::Unwinder* unwinder) const {
const char *error_type_str;
switch (report->error_type) {
case USE_AFTER_FREE:
error_type_str = "Use After Free";
break;
case BUFFER_OVERFLOW:
error_type_str = "Buffer Overflow";
break;
case BUFFER_UNDERFLOW:
error_type_str = "Buffer Underflow";
break;
default:
error_type_str = "Unknown";
break;
}
uintptr_t diff;
const char* location_str;
if (untagged_fault_addr_ < report->allocation_address) {
// Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef.
location_str = "left of";
diff = report->allocation_address - untagged_fault_addr_;
} else if (untagged_fault_addr_ - report->allocation_address < report->allocation_size) {
// Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef.
location_str = "into";
diff = untagged_fault_addr_ - report->allocation_address;
} else {
// Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef.
location_str = "right of";
diff = untagged_fault_addr_ - report->allocation_address - report->allocation_size;
}
// Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'.
const char* byte_suffix = "s";
if (diff == 1) {
byte_suffix = "";
}
_LOG(log, logtype::HEADER,
"\nCause: [MTE]: %s, %" PRIuPTR " byte%s %s a %zu-byte allocation at 0x%" PRIxPTR "\n",
error_type_str, diff, byte_suffix, location_str, report->allocation_size,
report->allocation_address);
if (report->allocation_trace[0]) {
_LOG(log, logtype::BACKTRACE, "\nallocated by thread %u:\n", report->allocation_tid);
unwinder->SetDisplayBuildID(true);
for (size_t i = 0; i < arraysize(report->allocation_trace) && report->allocation_trace[i];
++i) {
unwindstack::FrameData frame_data =
unwinder->BuildFrameFromPcOnly(report->allocation_trace[i]);
frame_data.num = i;
_LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
}
}
if (report->deallocation_trace[0]) {
_LOG(log, logtype::BACKTRACE, "\ndeallocated by thread %u:\n", report->deallocation_tid);
unwinder->SetDisplayBuildID(true);
for (size_t i = 0; i < arraysize(report->deallocation_trace) && report->deallocation_trace[i];
++i) {
unwindstack::FrameData frame_data =
unwinder->BuildFrameFromPcOnly(report->deallocation_trace[i]);
frame_data.num = i;
_LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
}
}
}

View file

@ -1,205 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <sys/mman.h>
#include <time.h>
#include <memory>
#include <string>
#include <android-base/file.h>
#include <android-base/properties.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "libdebuggerd/utility.h"
#include "UnwinderMock.h"
#include "host_signal_fixup.h"
#include "log_fake.h"
#include "gwp_asan.cpp"
using ::testing::MatchesRegex;
class TombstoneTest : public ::testing::Test {
protected:
virtual void SetUp() {
unwinder_mock_.reset(new UnwinderMock());
char tmp_file[256];
const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
memcpy(tmp_file, data_template, sizeof(data_template));
int tombstone_fd = mkstemp(tmp_file);
if (tombstone_fd == -1) {
const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
memcpy(tmp_file, tmp_template, sizeof(tmp_template));
tombstone_fd = mkstemp(tmp_file);
if (tombstone_fd == -1) {
abort();
}
}
if (unlink(tmp_file) == -1) {
abort();
}
log_.tfd = tombstone_fd;
amfd_data_.clear();
log_.amfd_data = &amfd_data_;
log_.crashed_tid = 12;
log_.current_tid = 12;
log_.should_retrieve_logcat = false;
resetLogs();
}
virtual void TearDown() {
if (log_.tfd >= 0) {
close(log_.tfd);
}
}
std::unique_ptr<UnwinderMock> unwinder_mock_;
log_t log_;
std::string amfd_data_;
};
class GwpAsanCrashDataTest : public GwpAsanCrashData {
public:
GwpAsanCrashDataTest(
gwp_asan::Error error,
const gwp_asan::AllocationMetadata *responsible_allocation) :
GwpAsanCrashData(nullptr, ProcessInfo{}, ThreadInfo{}) {
is_gwp_asan_responsible_ = true;
error_ = error;
responsible_allocation_ = responsible_allocation;
error_string_ = gwp_asan::ErrorToString(error_);
}
void SetCrashAddress(uintptr_t crash_address) {
crash_address_ = crash_address;
}
};
TEST_F(TombstoneTest, gwp_asan_cause_uaf_exact) {
gwp_asan::AllocationMetadata meta;
meta.Addr = 0x1000;
meta.RequestedSize = 32;
GwpAsanCrashDataTest crash_data(gwp_asan::Error::USE_AFTER_FREE, &meta);
crash_data.SetCrashAddress(0x1000);
crash_data.DumpCause(&log_);
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
std::string tombstone_contents;
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_THAT(tombstone_contents, MatchesRegex("Cause: \\[GWP-ASan\\]: Use After Free, 0 bytes "
"into a 32-byte allocation at 0x[a-fA-F0-9]+\n"));
}
TEST_F(TombstoneTest, gwp_asan_cause_double_free) {
gwp_asan::AllocationMetadata meta;
meta.Addr = 0x1000;
meta.RequestedSize = 32;
GwpAsanCrashDataTest crash_data(gwp_asan::Error::DOUBLE_FREE, &meta);
crash_data.SetCrashAddress(0x1000);
crash_data.DumpCause(&log_);
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
std::string tombstone_contents;
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_THAT(tombstone_contents, MatchesRegex("Cause: \\[GWP-ASan\\]: Double Free, 0 bytes into a "
"32-byte allocation at 0x[a-fA-F0-9]+\n"));
}
TEST_F(TombstoneTest, gwp_asan_cause_overflow) {
gwp_asan::AllocationMetadata meta;
meta.Addr = 0x1000;
meta.RequestedSize = 32;
GwpAsanCrashDataTest crash_data(gwp_asan::Error::BUFFER_OVERFLOW, &meta);
crash_data.SetCrashAddress(0x1025);
crash_data.DumpCause(&log_);
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
std::string tombstone_contents;
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_THAT(
tombstone_contents,
MatchesRegex(
"Cause: \\[GWP-ASan\\]: Buffer Overflow, 5 bytes right of a 32-byte "
"allocation at 0x[a-fA-F0-9]+\n"));
}
TEST_F(TombstoneTest, gwp_asan_cause_underflow) {
gwp_asan::AllocationMetadata meta;
meta.Addr = 0x1000;
meta.RequestedSize = 32;
GwpAsanCrashDataTest crash_data(gwp_asan::Error::BUFFER_UNDERFLOW, &meta);
crash_data.SetCrashAddress(0xffe);
crash_data.DumpCause(&log_);
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
std::string tombstone_contents;
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_THAT(
tombstone_contents,
MatchesRegex(
"Cause: \\[GWP-ASan\\]: Buffer Underflow, 2 bytes left of a 32-byte "
"allocation at 0x[a-fA-F0-9]+\n"));
}
TEST_F(TombstoneTest, gwp_asan_cause_invalid_free_inside) {
gwp_asan::AllocationMetadata meta;
meta.Addr = 0x1000;
meta.RequestedSize = 32;
GwpAsanCrashDataTest crash_data(gwp_asan::Error::INVALID_FREE, &meta);
crash_data.SetCrashAddress(0x1001);
crash_data.DumpCause(&log_);
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
std::string tombstone_contents;
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_THAT(
tombstone_contents,
MatchesRegex(
"Cause: \\[GWP-ASan\\]: Invalid \\(Wild\\) Free, 1 byte into a 32-byte "
"allocation at 0x[a-fA-F0-9]+\n"));
}
TEST_F(TombstoneTest, gwp_asan_cause_invalid_free_outside) {
gwp_asan::AllocationMetadata meta;
meta.Addr = 0x1000;
meta.RequestedSize = 32;
GwpAsanCrashDataTest crash_data(gwp_asan::Error::INVALID_FREE, &meta);
crash_data.SetCrashAddress(0x1021);
crash_data.DumpCause(&log_);
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
std::string tombstone_contents;
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_THAT(
tombstone_contents,
MatchesRegex(
"Cause: \\[GWP-ASan\\]: Invalid \\(Wild\\) Free, 33 bytes right of a 32-byte "
"allocation at 0x[a-fA-F0-9]+\n"));
}