diff options
author | Scott Lobdell <slobdell@google.com> | 2021-04-07 05:35:55 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-04-07 05:35:55 +0000 |
commit | ec6cfacad7283c60a33cfefacf5031247a2f81dc (patch) | |
tree | 5b473e86fc8ab0afc2241b6ac25875b25fa354bd /debuggerd/libdebuggerd/tombstone_proto.cpp | |
parent | 79aff2b0a0653fcafaf9099ad60075f2903e8de1 (diff) | |
parent | 268fff7088f0ab311c2de902178054ce40a42243 (diff) |
Merge "Merge SP1A.210329.001" into s-keystone-qcom-dev
Diffstat (limited to 'debuggerd/libdebuggerd/tombstone_proto.cpp')
-rw-r--r-- | debuggerd/libdebuggerd/tombstone_proto.cpp | 236 |
1 files changed, 179 insertions, 57 deletions
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp index 23ca070e5..3444e29e1 100644 --- a/debuggerd/libdebuggerd/tombstone_proto.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto.cpp @@ -17,6 +17,8 @@ #define LOG_TAG "DEBUG" #include "libdebuggerd/tombstone.h" +#include "libdebuggerd/gwp_asan.h" +#include "libdebuggerd/scudo.h" #include <errno.h> #include <fcntl.h> @@ -29,10 +31,12 @@ #include <time.h> #include <memory> +#include <optional> #include <string> #include <async_safe/log.h> +#include <android-base/file.h> #include <android-base/properties.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> @@ -45,6 +49,7 @@ #include <log/logprint.h> #include <private/android_filesystem_config.h> +#include <procinfo/process.h> #include <unwindstack/Maps.h> #include <unwindstack/Memory.h> #include <unwindstack/Regs.h> @@ -106,32 +111,120 @@ static std::optional<std::string> get_stack_overflow_cause(uint64_t fault_addr, return {}; } -static void dump_probable_cause(Tombstone* tombstone, const siginfo_t* si, unwindstack::Maps* maps, - unwindstack::Regs* regs) { +void set_human_readable_cause(Cause* cause, uint64_t fault_addr) { + if (!cause->has_memory_error() || !cause->memory_error().has_heap()) { + return; + } + + const MemoryError& memory_error = cause->memory_error(); + const HeapObject& heap_object = memory_error.heap(); + + const char *tool_str; + switch (memory_error.tool()) { + case MemoryError_Tool_GWP_ASAN: + tool_str = "GWP-ASan"; + break; + case MemoryError_Tool_SCUDO: + tool_str = "MTE"; + break; + default: + tool_str = "Unknown"; + break; + } + + const char *error_type_str; + switch (memory_error.type()) { + case MemoryError_Type_USE_AFTER_FREE: + error_type_str = "Use After Free"; + break; + case MemoryError_Type_DOUBLE_FREE: + error_type_str = "Double Free"; + break; + case MemoryError_Type_INVALID_FREE: + error_type_str = "Invalid (Wild) Free"; + break; + case MemoryError_Type_BUFFER_OVERFLOW: + error_type_str = "Buffer Overflow"; + break; + case MemoryError_Type_BUFFER_UNDERFLOW: + error_type_str = "Buffer Underflow"; + break; + default: + cause->set_human_readable( + StringPrintf("[%s]: Unknown error occurred at 0x%" PRIx64 ".", tool_str, fault_addr)); + return; + } + + uint64_t diff; + const char* location_str; + + if (fault_addr < heap_object.address()) { + // Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef. + location_str = "left of"; + diff = heap_object.address() - fault_addr; + } else if (fault_addr - heap_object.address() < heap_object.size()) { + // Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef. + location_str = "into"; + diff = fault_addr - heap_object.address(); + } else { + // Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef. + location_str = "right of"; + diff = fault_addr - heap_object.address() - heap_object.size(); + } + + // Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'. + const char* byte_suffix = "s"; + if (diff == 1) { + byte_suffix = ""; + } + + cause->set_human_readable(StringPrintf( + "[%s]: %s, %" PRIu64 " byte%s %s a %" PRIu64 "-byte allocation at 0x%" PRIx64, tool_str, + error_type_str, diff, byte_suffix, location_str, heap_object.size(), heap_object.address())); +} + +static void dump_probable_cause(Tombstone* tombstone, unwindstack::Unwinder* unwinder, + const ProcessInfo& process_info, const ThreadInfo& main_thread) { + ScudoCrashData scudo_crash_data(unwinder->GetProcessMemory().get(), process_info); + if (scudo_crash_data.CrashIsMine()) { + scudo_crash_data.AddCauseProtos(tombstone, unwinder); + return; + } + + GwpAsanCrashData gwp_asan_crash_data(unwinder->GetProcessMemory().get(), process_info, + main_thread); + if (gwp_asan_crash_data.CrashIsMine()) { + gwp_asan_crash_data.AddCauseProtos(tombstone, unwinder); + return; + } + + const siginfo *si = main_thread.siginfo; + auto fault_addr = reinterpret_cast<uint64_t>(si->si_addr); + unwindstack::Maps* maps = unwinder->GetMaps(); + std::optional<std::string> cause; if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) { - if (si->si_addr < reinterpret_cast<void*>(4096)) { + if (fault_addr < 4096) { cause = "null pointer dereference"; - } else if (si->si_addr == reinterpret_cast<void*>(0xffff0ffc)) { + } else if (fault_addr == 0xffff0ffc) { cause = "call to kuser_helper_version"; - } else if (si->si_addr == reinterpret_cast<void*>(0xffff0fe0)) { + } else if (fault_addr == 0xffff0fe0) { cause = "call to kuser_get_tls"; - } else if (si->si_addr == reinterpret_cast<void*>(0xffff0fc0)) { + } else if (fault_addr == 0xffff0fc0) { cause = "call to kuser_cmpxchg"; - } else if (si->si_addr == reinterpret_cast<void*>(0xffff0fa0)) { + } else if (fault_addr == 0xffff0fa0) { cause = "call to kuser_memory_barrier"; - } else if (si->si_addr == reinterpret_cast<void*>(0xffff0f60)) { + } else if (fault_addr == 0xffff0f60) { cause = "call to kuser_cmpxchg64"; } else { - cause = get_stack_overflow_cause(reinterpret_cast<uint64_t>(si->si_addr), regs->sp(), maps); + cause = get_stack_overflow_cause(fault_addr, main_thread.registers->sp(), maps); } } else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) { - uint64_t fault_addr = reinterpret_cast<uint64_t>(si->si_addr); unwindstack::MapInfo* map_info = maps->Find(fault_addr); if (map_info != nullptr && map_info->flags == PROT_EXEC) { cause = "execute-only (no-read) memory access error; likely due to data in .text."; } else { - cause = get_stack_overflow_cause(fault_addr, regs->sp(), maps); + cause = get_stack_overflow_cause(fault_addr, main_thread.registers->sp(), maps); } } else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) { cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING, @@ -139,7 +232,8 @@ static void dump_probable_cause(Tombstone* tombstone, const siginfo_t* si, unwin } if (cause) { - tombstone->mutable_cause()->set_human_readable(*cause); + Cause *cause_proto = tombstone->add_causes(); + cause_proto->set_human_readable(*cause); } } @@ -205,12 +299,49 @@ static void dump_open_fds(Tombstone* tombstone, const OpenFilesList* open_files) } } +void fill_in_backtrace_frame(BacktraceFrame* f, const unwindstack::FrameData& frame, + unwindstack::Maps* maps) { + f->set_rel_pc(frame.rel_pc); + f->set_pc(frame.pc); + f->set_sp(frame.sp); + + if (!frame.function_name.empty()) { + // TODO: Should this happen here, or on the display side? + char* demangled_name = __cxa_demangle(frame.function_name.c_str(), nullptr, nullptr, nullptr); + if (demangled_name) { + f->set_function_name(demangled_name); + free(demangled_name); + } else { + f->set_function_name(frame.function_name); + } + } + + f->set_function_offset(frame.function_offset); + + if (frame.map_start == frame.map_end) { + // No valid map associated with this frame. + f->set_file_name("<unknown>"); + } else if (!frame.map_name.empty()) { + f->set_file_name(frame.map_name); + } else { + f->set_file_name(StringPrintf("<anonymous:%" PRIx64 ">", frame.map_start)); + } + + f->set_file_map_offset(frame.map_elf_start_offset); + + unwindstack::MapInfo* map_info = maps->Find(frame.map_start); + if (map_info) { + f->set_build_id(map_info->GetPrintableBuildID()); + } +} + static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info, bool memory_dump = false) { Thread thread; thread.set_id(thread_info.tid); thread.set_name(thread_info.thread_name); + thread.set_tagged_addr_ctrl(thread_info.tagged_addr_ctrl); unwindstack::Maps* maps = unwinder->GetMaps(); unwindstack::Memory* memory = unwinder->GetProcessMemory().get(); @@ -225,20 +356,19 @@ static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, if (memory_dump) { MemoryDump dump; - char buf[256]; - size_t start_offset = 0; - ssize_t bytes = dump_memory(buf, sizeof(buf), &start_offset, &value, memory); - if (bytes == -1) { - return; - } - dump.set_register_name(name); - unwindstack::MapInfo* map_info = maps->Find(untag_address(value)); if (map_info) { dump.set_mapping_name(map_info->name); } + char buf[256]; + uint8_t tags[256 / kTagGranuleSize]; + size_t start_offset = 0; + ssize_t bytes = dump_memory(buf, sizeof(buf), tags, sizeof(tags), &value, memory); + if (bytes == -1) { + return; + } dump.set_begin_address(value); if (start_offset + bytes > sizeof(buf)) { @@ -246,7 +376,8 @@ static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, start_offset, bytes); } - dump.set_memory(buf, start_offset + bytes); + dump.set_memory(buf, bytes); + dump.set_tags(tags, bytes / kTagGranuleSize); *thread.add_memory_dump() = std::move(dump); } @@ -267,39 +398,7 @@ static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, unwinder->SetDisplayBuildID(true); for (const auto& frame : unwinder->frames()) { BacktraceFrame* f = thread.add_current_backtrace(); - f->set_rel_pc(frame.rel_pc); - f->set_pc(frame.pc); - f->set_sp(frame.sp); - - if (!frame.function_name.empty()) { - // TODO: Should this happen here, or on the display side? - char* demangled_name = - __cxa_demangle(frame.function_name.c_str(), nullptr, nullptr, nullptr); - if (demangled_name) { - f->set_function_name(demangled_name); - free(demangled_name); - } else { - f->set_function_name(frame.function_name); - } - } - - f->set_function_offset(frame.function_offset); - - if (frame.map_start == frame.map_end) { - // No valid map associated with this frame. - f->set_file_name("<unknown>"); - } else if (!frame.map_name.empty()) { - f->set_file_name(frame.map_name); - } else { - f->set_file_name(StringPrintf("<anonymous:%" PRIx64 ">", frame.map_start)); - } - - f->set_file_map_offset(frame.map_elf_start_offset); - - unwindstack::MapInfo* map_info = maps->Find(frame.map_start); - if (map_info) { - f->set_build_id(map_info->GetPrintableBuildID()); - } + fill_in_backtrace_frame(f, frame, maps); } } @@ -423,6 +522,14 @@ static void dump_logcat(Tombstone* tombstone, pid_t pid) { dump_log_file(tombstone, "main", pid); } +static std::optional<uint64_t> read_uptime_secs() { + std::string uptime; + if (!android::base::ReadFileToString("/proc/uptime", &uptime)) { + return {}; + } + return strtoll(uptime.c_str(), nullptr, 10); +} + void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwinder, const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread, const ProcessInfo& process_info, const OpenFilesList* open_files) { @@ -433,6 +540,22 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwind result.set_revision(android::base::GetProperty("ro.revision", "unknown")); result.set_timestamp(get_timestamp()); + std::optional<uint64_t> system_uptime = read_uptime_secs(); + if (system_uptime) { + android::procinfo::ProcessInfo proc_info; + std::string error; + if (android::procinfo::GetProcessInfo(target_thread, &proc_info, &error)) { + uint64_t starttime = proc_info.starttime / sysconf(_SC_CLK_TCK); + result.set_process_uptime(*system_uptime - starttime); + } else { + async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to read process info: %s", + error.c_str()); + } + } else { + async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to read /proc/uptime: %s", + strerror(errno)); + } + const ThreadInfo& main_thread = threads.at(target_thread); result.set_pid(main_thread.pid); result.set_tid(main_thread.tid); @@ -458,7 +581,7 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwind if (process_info.has_fault_address) { sig.set_has_fault_address(true); - sig.set_fault_address(process_info.untagged_fault_address); + sig.set_fault_address(process_info.maybe_tagged_fault_address); } *result.mutable_signal_info() = sig; @@ -473,8 +596,7 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwind } } - dump_probable_cause(&result, main_thread.siginfo, unwinder->GetMaps(), - main_thread.registers.get()); + dump_probable_cause(&result, unwinder, process_info, main_thread); dump_mappings(&result, unwinder); |