[Lldb-commits] [lldb] 256c16e - Change debugserver to clear PAC auth bits manually

Jason Molenda via lldb-commits lldb-commits at lists.llvm.org
Tue Oct 25 13:49:08 PDT 2022


Author: Jason Molenda
Date: 2022-10-25T13:49:05-07:00
New Revision: 256c16e8f4e483ff19ed7096d3c41947a8a93144

URL: https://github.com/llvm/llvm-project/commit/256c16e8f4e483ff19ed7096d3c41947a8a93144
DIFF: https://github.com/llvm/llvm-project/commit/256c16e8f4e483ff19ed7096d3c41947a8a93144.diff

LOG: Change debugserver to clear PAC auth bits manually

debugserver is currently using kernel supplied macros,
arm_thread_state64_get_{pc,fp,sp,lr} which can crash on an authorization
failure when the inferior has crashed with an invalid pc value, for
instance.  debugserver needs to be resistant to crashing in this
scenario, and we're merely clearing the bits, so do it with a bit
mask operation instead.

Differential Revision: https://reviews.llvm.org/D136620
rdar://98073271
rdar://100663221

Added: 
    

Modified: 
    lldb/tools/debugserver/source/DNB.cpp
    lldb/tools/debugserver/source/DNB.h
    lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp
    lldb/tools/debugserver/source/RNBRemote.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp
index ebb76074670b1..7c6fd4b0177b0 100644
--- a/lldb/tools/debugserver/source/DNB.cpp
+++ b/lldb/tools/debugserver/source/DNB.cpp
@@ -1824,3 +1824,19 @@ bool DNBDebugserverIsTranslated() {
     return false;
   return ret == 1;
 }
+
+bool DNBGetAddressingBits(uint32_t &addressing_bits) {
+  static uint32_t g_addressing_bits = 0;
+  static std::once_flag g_once_flag;
+  std::call_once(g_once_flag, [&](){
+    size_t len = sizeof(uint32_t);
+    if (::sysctlbyname("machdep.virtual_address_size", &g_addressing_bits, &len,
+                       NULL, 0) != 0) {
+      g_addressing_bits = 0;
+    }
+  }
+
+  addressing_bits = g_addressing_bits;
+
+  return addressing_bits > 0;
+}

diff  --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h
index f29078ce6c145..b0ab37adad00c 100644
--- a/lldb/tools/debugserver/source/DNB.h
+++ b/lldb/tools/debugserver/source/DNB.h
@@ -245,4 +245,6 @@ std::string DNBGetMacCatalystVersionString();
 /// \return true if debugserver is running in translation
 /// (is an x86_64 process on arm64)
 bool DNBDebugserverIsTranslated();
+
+bool DNBGetAddressingBits(uint32_t &addressing_bits);
 #endif

diff  --git a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp
index fa4ba5f67263a..5a8a256948023 100644
--- a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp
@@ -94,11 +94,35 @@ DNBArchMachARM64::SoftwareBreakpointOpcode(nub_size_t byte_size) {
 
 uint32_t DNBArchMachARM64::GetCPUType() { return CPU_TYPE_ARM64; }
 
+static uint64_t clear_pac_bits(uint64_t value) {
+  uint32_t addressing_bits = 0;
+  if (!DNBGetAddressingBits(addressing_bits))
+    return value;
+
+    // On arm64_32, no ptrauth bits to clear
+#if !defined(__LP64__)
+  return value;
+#endif
+
+  uint64_t mask = ((1ULL << addressing_bits) - 1);
+
+  // Normally PAC bit clearing needs to check b55 and either set the
+  // non-addressing bits, or clear them.  But the register values we
+  // get from thread_get_state on an arm64e process don't follow this
+  // convention?, at least when there's been a PAC auth failure in
+  // the inferior.
+  // Userland processes are always in low memory, so this
+  // hardcoding b55 == 0 PAC stripping behavior here.
+
+  return value & mask; // high bits cleared to 0
+}
+
 uint64_t DNBArchMachARM64::GetPC(uint64_t failValue) {
   // Get program counter
   if (GetGPRState(false) == KERN_SUCCESS)
-#if defined(__LP64__)
-    return arm_thread_state64_get_pc(m_state.context.gpr);
+#if __has_feature(ptrauth_calls) && defined(__LP64__)
+    return clear_pac_bits(
+        reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_pc));
 #else
     return m_state.context.gpr.__pc;
 #endif
@@ -128,8 +152,9 @@ kern_return_t DNBArchMachARM64::SetPC(uint64_t value) {
 uint64_t DNBArchMachARM64::GetSP(uint64_t failValue) {
   // Get stack pointer
   if (GetGPRState(false) == KERN_SUCCESS)
-#if defined(__LP64__)
-    return arm_thread_state64_get_sp(m_state.context.gpr);
+#if __has_feature(ptrauth_calls) && defined(__LP64__)
+    return clear_pac_bits(
+        reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_sp));
 #else
     return m_state.context.gpr.__sp;
 #endif
@@ -150,16 +175,20 @@ kern_return_t DNBArchMachARM64::GetGPRState(bool force) {
   if (DNBLogEnabledForAny(LOG_THREAD)) {
     uint64_t *x = &m_state.context.gpr.__x[0];
 
-#if defined(__LP64__)
-        uint64_t log_fp = arm_thread_state64_get_fp(m_state.context.gpr);
-        uint64_t log_lr = arm_thread_state64_get_lr(m_state.context.gpr);
-        uint64_t log_sp = arm_thread_state64_get_sp(m_state.context.gpr);
-        uint64_t log_pc = arm_thread_state64_get_pc(m_state.context.gpr);
+#if __has_feature(ptrauth_calls) && defined(__LP64__)
+    uint64_t log_fp = clear_pac_bits(
+        reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_fp));
+    uint64_t log_lr = clear_pac_bits(
+        reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_lr));
+    uint64_t log_sp = clear_pac_bits(
+        reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_sp));
+    uint64_t log_pc = clear_pac_bits(
+        reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_pc));
 #else
-        uint64_t log_fp = m_state.context.gpr.__fp;
-        uint64_t log_lr = m_state.context.gpr.__lr;
-        uint64_t log_sp = m_state.context.gpr.__sp;
-        uint64_t log_pc = m_state.context.gpr.__pc;
+    uint64_t log_fp = m_state.context.gpr.__fp;
+    uint64_t log_lr = m_state.context.gpr.__lr;
+    uint64_t log_sp = m_state.context.gpr.__sp;
+    uint64_t log_pc = m_state.context.gpr.__pc;
 #endif
     DNBLogThreaded(
         "thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count = %u) regs"
@@ -617,8 +646,9 @@ kern_return_t DNBArchMachARM64::EnableHardwareSingleStep(bool enable) {
     return err.Status();
   }
 
-#if defined(__LP64__)
-  uint64_t pc = arm_thread_state64_get_pc (m_state.context.gpr);
+#if __has_feature(ptrauth_calls) && defined(__LP64__)
+  uint64_t pc = clear_pac_bits(
+      reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_pc));
 #else
   uint64_t pc = m_state.context.gpr.__pc;
 #endif
@@ -1992,20 +2022,10 @@ bool DNBArchMachARM64::GetRegisterValue(uint32_t set, uint32_t reg,
     switch (set) {
     case e_regSetGPR:
       if (reg <= gpr_pc) {
-#if defined(__LP64__)
-        if (reg == gpr_pc)
-          value->value.uint64 = arm_thread_state64_get_pc (m_state.context.gpr);
-        else if (reg == gpr_lr)
-          value->value.uint64 = arm_thread_state64_get_lr (m_state.context.gpr);
-        else if (reg == gpr_sp)
-          value->value.uint64 = arm_thread_state64_get_sp (m_state.context.gpr);
-        else if (reg == gpr_fp)
-          value->value.uint64 = arm_thread_state64_get_fp (m_state.context.gpr);
+        if (reg == gpr_pc || reg == gpr_lr || reg == gpr_sp || reg == gpr_fp)
+          value->value.uint64 = clear_pac_bits(m_state.context.gpr.__x[reg]);
         else
-        value->value.uint64 = m_state.context.gpr.__x[reg];
-#else
-        value->value.uint64 = m_state.context.gpr.__x[reg];
-#endif
+          value->value.uint64 = m_state.context.gpr.__x[reg];
         return true;
       } else if (reg == gpr_cpsr) {
         value->value.uint32 = m_state.context.gpr.__cpsr;

diff  --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
index ebb2125524e9c..48de97f1f6a47 100644
--- a/lldb/tools/debugserver/source/RNBRemote.cpp
+++ b/lldb/tools/debugserver/source/RNBRemote.cpp
@@ -4781,24 +4781,6 @@ static bool GetHostCPUType(uint32_t &cputype, uint32_t &cpusubtype,
   return g_host_cputype != 0;
 }
 
-static bool GetAddressingBits(uint32_t &addressing_bits) {
-  static uint32_t g_addressing_bits = 0;
-  static bool g_tried_addressing_bits_syscall = false;
-  if (g_tried_addressing_bits_syscall == false) {
-    size_t len = sizeof (uint32_t);
-    if (::sysctlbyname("machdep.virtual_address_size",
-          &g_addressing_bits, &len, NULL, 0) != 0) {
-      g_addressing_bits = 0;
-    }
-  }
-  g_tried_addressing_bits_syscall = true;
-  addressing_bits = g_addressing_bits;
-  if (addressing_bits > 0)
-    return true;
-  else
-    return false;
-}
-
 rnb_err_t RNBRemote::HandlePacket_qHostInfo(const char *p) {
   std::ostringstream strm;
 
@@ -4812,7 +4794,7 @@ rnb_err_t RNBRemote::HandlePacket_qHostInfo(const char *p) {
   }
 
   uint32_t addressing_bits = 0;
-  if (GetAddressingBits(addressing_bits)) {
+  if (DNBGetAddressingBits(addressing_bits)) {
     strm << "addressing_bits:" << std::dec << addressing_bits << ';';
   }
 


        


More information about the lldb-commits mailing list