Read fault address on arm64 using proposed kernel API.

On aarch64, the top 8 bits of the address (i.e. the tag bits) of
the fault address in si_addr are always clear. This isn't ideal for
MTE which will require these bits in order to correctly diagnose
tag mismatches.

A proposed kernel patch [1] exposes the full fault address including
the tag bits as part of the ucontext. Change debuggerd to read this
fault address if available.

[1] https://patchwork.kernel.org/patch/11435077/

Bug: 135772972
Change-Id: Ia05be574113860f4e9ecc36a310c4b740e0c4afb
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 087ebae..0cd2350 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -295,6 +295,13 @@
     case 3:
       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);
+      }
       regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(),
                                                         &crash_info->data.s.ucontext));
       break;
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 6a8cc56..054f836 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -305,6 +305,32 @@
   ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
 }
 
+TEST_F(CrasherTest, tagged_fault_addr) {
+#if !defined(__aarch64__)
+  GTEST_SKIP() << "Requires aarch64";
+#endif
+  int intercept_result;
+  unique_fd output_fd;
+  StartProcess([]() {
+    *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
+  });
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGSEGV);
+  FinishIntercept(&intercept_result);
+
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+
+  // The address can either be tagged (new kernels) or untagged (old kernels).
+  ASSERT_MATCH(
+      result,
+      R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr (0x100000000000dead|0xdead))");
+}
+
 TEST_F(CrasherTest, LD_PRELOAD) {
   int intercept_result;
   unique_fd output_fd;
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 84d2bd0..003c3d9 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -167,7 +167,7 @@
  * 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) {
+static void log_signal_summary(const siginfo_t* info, const ucontext_t* ucontext) {
   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,7 +186,8 @@
   // 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", info->si_addr);
+    async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p",
+                             reinterpret_cast<void*>(get_fault_address(info, ucontext)));
   }
   pid_t self_pid = __getpid();
   char sender_desc[32] = {};  // " from pid 1234, uid 666"
@@ -476,6 +477,8 @@
   // making a syscall and checking errno.
   ErrnoRestorer restorer;
 
+  auto *ucontext = static_cast<ucontext_t*>(context);
+
   // It's possible somebody cleared the SA_SIGINFO flag, which would mean
   // our "info" arg holds an undefined value.
   if (!have_siginfo(signal_number)) {
@@ -522,7 +525,7 @@
     // This check might be racy if another thread sets NO_NEW_PRIVS, but this should be unlikely,
     // you can only set NO_NEW_PRIVS to 1, and the effect should be at worst a single missing
     // ANR trace.
-    debuggerd_fallback_handler(info, static_cast<ucontext_t*>(context), process_info.abort_msg);
+    debuggerd_fallback_handler(info, ucontext, process_info.abort_msg);
     resend_signal(info);
     return;
   }
@@ -534,7 +537,7 @@
     return;
   }
 
-  log_signal_summary(info);
+  log_signal_summary(info, ucontext);
 
   debugger_thread_info thread_info = {
       .crashing_tid = __gettid(),
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index 4f681c2..35c3fd6 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -41,4 +41,7 @@
   uintptr_t fdsan_table_address = 0;
   uintptr_t gwp_asan_state = 0;
   uintptr_t gwp_asan_metadata = 0;
+
+  bool has_fault_address = false;
+  uintptr_t fault_address = 0;
 };
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 75bac87..7bfcf5d 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -93,4 +93,6 @@
 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/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index b3f059c..70b8817 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -154,16 +154,16 @@
 }
 
 static void dump_signal_info(log_t* log, const ThreadInfo& thread_info,
-                             unwindstack::Memory* process_memory) {
+                             const ProcessInfo& process_info, unwindstack::Memory* process_memory) {
   char addr_desc[64];  // ", fault addr 0x1234"
-  if (signal_has_si_addr(thread_info.siginfo)) {
-    void* addr = thread_info.siginfo->si_addr;
+  if (process_info.has_fault_address) {
+    size_t addr = process_info.fault_address;
     if (thread_info.siginfo->si_signo == SIGILL) {
       uint32_t instruction = {};
-      process_memory->Read(reinterpret_cast<uint64_t>(addr), &instruction, sizeof(instruction));
-      snprintf(addr_desc, sizeof(addr_desc), "%p (*pc=%#08x)", addr, instruction);
+      process_memory->Read(addr, &instruction, sizeof(instruction));
+      snprintf(addr_desc, sizeof(addr_desc), "0x%zx (*pc=%#08x)", addr, instruction);
     } else {
-      snprintf(addr_desc, sizeof(addr_desc), "%p", addr);
+      snprintf(addr_desc, sizeof(addr_desc), "0x%zx", addr);
     }
   } else {
     snprintf(addr_desc, sizeof(addr_desc), "--------");
@@ -384,7 +384,7 @@
   dump_thread_info(log, thread_info);
 
   if (thread_info.siginfo) {
-    dump_signal_info(log, thread_info, unwinder->GetProcessMemory().get());
+    dump_signal_info(log, thread_info, process_info, unwinder->GetProcessMemory().get());
   }
 
   std::unique_ptr<GwpAsanCrashData> gwp_asan_crash_data;
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 0a1d2a4..3bf28b6 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -449,3 +449,40 @@
     _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);
+}