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
This commit is contained in:
Peter Collingbourne 2020-11-13 10:54:13 -08:00
parent 13e33f7f80
commit ebc78cc852
4 changed files with 10 additions and 47 deletions

View File

@ -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<uintptr_t>(siginfo->si_addr);
}
regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(),
&crash_info->data.s.ucontext));

View File

@ -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<unsigned long>(thread_name), 0, 0, 0) != 0) {
strcpy(thread_name, "<name unknown>");
@ -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<void*>(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);
}

View File

@ -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

View File

@ -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<const char*>(ucontext->uc_mcontext.__reserved);
auto* end = begin + sizeof(ucontext->uc_mcontext.__reserved);
auto* ptr = begin;
while (1) {
auto* ctx = reinterpret_cast<const _aarch64_ctx*>(ptr);
if (ctx->magic == 0) {
break;
}
if (ctx->magic == FAR_MAGIC) {
auto* far_ctx = reinterpret_cast<const far_context*>(ctx);
return far_ctx->far;
}
ptr += ctx->size;
if (ctx->size % sizeof(void*) != 0 || ptr < begin || ptr >= end) {
break;
}
}
#endif
return reinterpret_cast<uintptr_t>(siginfo->si_addr);
}