From ebc78cc8523b1047d9d7eca1cf183f39a6b06480 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Fri, 13 Nov 2020 10:54:13 -0800 Subject: [PATCH] Switch to the new kernel API for obtaining fault address tag bits. The discussion on LKML is converging on v16 of the fault address tag bits patch [1]. In this version of the patch the presence of the tag bits in si_addr is controlled by a sa_flags bit, and a protocol is introduced to allow userspace to detect kernel support for sa_flags bits. Update the tombstone signal handler to use this API to read the tag bits, update the interceptors in libsigchain to implement the flag support detection protocol and hide the tag bits in si_addr from chained signal handlers that did not request them to match the kernel behavior. [1] https://lore.kernel.org/linux-arm-kernel/cover.1605235762.git.pcc@google.com/ Change-Id: I57f24c07c01ceb3e5b81cfc15edf559ef7dfc740 --- debuggerd/crash_dump.cpp | 5 +-- debuggerd/handler/debuggerd_handler.cpp | 13 +++++-- .../include/libdebuggerd/utility.h | 2 - debuggerd/libdebuggerd/utility.cpp | 37 ------------------- 4 files changed, 10 insertions(+), 47 deletions(-) diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 528012198..b3e81b04b 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -299,11 +299,8 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo, process_info->abort_msg_address = crash_info->data.s.abort_msg_address; *siginfo = crash_info->data.s.siginfo; if (signal_has_si_addr(siginfo)) { - // Make a copy of the ucontext field because otherwise it is not aligned enough (due to - // being in a packed struct) and clang complains about that. - ucontext_t ucontext = crash_info->data.s.ucontext; process_info->has_fault_address = true; - process_info->fault_address = get_fault_address(siginfo, &ucontext); + process_info->fault_address = reinterpret_cast(siginfo->si_addr); } regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), &crash_info->data.s.ucontext)); diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp index 121a074d5..85ffc982a 100644 --- a/debuggerd/handler/debuggerd_handler.cpp +++ b/debuggerd/handler/debuggerd_handler.cpp @@ -167,7 +167,7 @@ static bool get_main_thread_name(char* buf, size_t len) { * mutex is being held, so we don't want to use any libc functions that * could allocate memory or hold a lock. */ -static void log_signal_summary(const siginfo_t* info, const ucontext_t* ucontext) { +static void log_signal_summary(const siginfo_t* info) { char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination if (prctl(PR_GET_NAME, reinterpret_cast(thread_name), 0, 0, 0) != 0) { strcpy(thread_name, ""); @@ -186,8 +186,7 @@ static void log_signal_summary(const siginfo_t* info, const ucontext_t* ucontext // Many signals don't have an address or sender. char addr_desc[32] = ""; // ", fault addr 0x1234" if (signal_has_si_addr(info)) { - async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", - reinterpret_cast(get_fault_address(info, ucontext))); + async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr); } pid_t self_pid = __getpid(); char sender_desc[32] = {}; // " from pid 1234, uid 666" @@ -544,7 +543,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c return; } - log_signal_summary(info, ucontext); + log_signal_summary(info); debugger_thread_info thread_info = { .crashing_tid = __gettid(), @@ -638,5 +637,11 @@ void debuggerd_init(debuggerd_callbacks_t* callbacks) { // Use the alternate signal stack if available so we can catch stack overflows. action.sa_flags |= SA_ONSTACK; + +#define SA_EXPOSE_TAGBITS 0x00000800 + // Request that the kernel set tag bits in the fault address. This is necessary for diagnosing MTE + // faults. + action.sa_flags |= SA_EXPOSE_TAGBITS; + debuggerd_register_handlers(&action); } diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h index 76155b183..29fb9a4f6 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h @@ -91,6 +91,4 @@ void get_signal_sender(char* buf, size_t n, const siginfo_t*); const char* get_signame(const siginfo_t*); const char* get_sigcode(const siginfo_t*); -uintptr_t get_fault_address(const siginfo_t* siginfo, const ucontext_t* ucontext); - #endif // _DEBUGGERD_UTILITY_H diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp index 4e6df09c9..d7067ca6e 100644 --- a/debuggerd/libdebuggerd/utility.cpp +++ b/debuggerd/libdebuggerd/utility.cpp @@ -451,40 +451,3 @@ void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* pref _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str()); } } - -#if defined(__aarch64__) -#define FAR_MAGIC 0x46415201 - -struct far_context { - struct _aarch64_ctx head; - __u64 far; -}; -#endif - -uintptr_t get_fault_address(const siginfo_t* siginfo, const ucontext_t* ucontext) { - (void)ucontext; -#if defined(__aarch64__) - // This relies on a kernel patch: - // https://patchwork.kernel.org/patch/11435077/ - // that hasn't been accepted into the kernel yet. TODO(pcc): Update this to - // use the official interface once it lands. - auto* begin = reinterpret_cast(ucontext->uc_mcontext.__reserved); - auto* end = begin + sizeof(ucontext->uc_mcontext.__reserved); - auto* ptr = begin; - while (1) { - auto* ctx = reinterpret_cast(ptr); - if (ctx->magic == 0) { - break; - } - if (ctx->magic == FAR_MAGIC) { - auto* far_ctx = reinterpret_cast(ctx); - return far_ctx->far; - } - ptr += ctx->size; - if (ctx->size % sizeof(void*) != 0 || ptr < begin || ptr >= end) { - break; - } - } -#endif - return reinterpret_cast(siginfo->si_addr); -}