https://github.com/ojhunt created 
https://github.com/llvm/llvm-project/pull/143230

This hardens the unwinding logic and datastructures on systems that support 
pointer authentication.

The approach taken to hardening is to harden the schemas of as many high value 
fields in the myriad structs as possible, and then also explicitly qualify 
local variables referencing privileged or security critical values.

This ABI is exposed to the personality functions, and so updating to conform to 
that is a mandatory change, but to reduce the risk of oracles, the adoption 
also hardened the locals and datastructures in compiler-rt and libcxxabi.

We're gating these on `defined(__APPLE__)` so other platforms are able to 
qualify before enabling. An alternative would be an feature flag that could be 
used instead but I didn't want to force such a change if it was not considered
necessary.

>From ad78fee1547cdd34315845a1c2b9c6872b810218 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oli...@apple.com>
Date: Fri, 6 Jun 2025 18:50:28 -0700
Subject: [PATCH] [runtimes][PAC] Harden unwinding when possible (#138571)

This hardens the unwinding logic and datastructures on systems
that support pointer authentication.

The approach taken to hardening is to harden the schemas of as many
high value fields in the myriad structs as possible, and then also
explicitly qualify local variables referencing privileged or security
critical values.

This ABI is exposed to the personality functions, and so updating to
conform to that is a mandatory change, but to reduce the risk of
oracles, the adoption also hardened the locals and datastructures
in compiler-rt and libcxxabi.
---
 compiler-rt/lib/builtins/gcc_personality_v0.c |  69 ++++++++++-
 compiler-rt/lib/profile/InstrProfilingValue.c |   8 +-
 libcxxabi/include/__cxxabi_config.h           |  48 +++++++-
 libcxxabi/src/cxa_exception.h                 |  30 ++---
 libcxxabi/src/cxa_personality.cpp             |  69 +++++++++--
 libunwind/include/libunwind.h                 |  78 ++++++++++--
 libunwind/src/AddressSpace.hpp                |  44 ++++---
 libunwind/src/DwarfInstructions.hpp           |  11 +-
 libunwind/src/DwarfParser.hpp                 |  44 ++++++-
 libunwind/src/Registers.hpp                   | 113 +++++++++++++++++-
 libunwind/src/UnwindCursor.hpp                |  72 ++++++++---
 libunwind/src/UnwindLevel1.c                  |  36 +++++-
 libunwind/src/UnwindRegistersSave.S           |  10 ++
 libunwind/src/libunwind.cpp                   |  34 ++++++
 14 files changed, 580 insertions(+), 86 deletions(-)

diff --git a/compiler-rt/lib/builtins/gcc_personality_v0.c 
b/compiler-rt/lib/builtins/gcc_personality_v0.c
index ef63a5fb83472..42b992949d2cc 100644
--- a/compiler-rt/lib/builtins/gcc_personality_v0.c
+++ b/compiler-rt/lib/builtins/gcc_personality_v0.c
@@ -30,6 +30,45 @@ EXCEPTION_DISPOSITION 
_GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
                                             _Unwind_Personality_Fn);
 #endif
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+#if __has_feature(ptrauth_restricted_intptr_qualifier)
+#define PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(key, addressDiscriminated,       
\
+                                              discriminatorString)             
\
+    __ptrauth_restricted_intptr(key, addressDiscriminated,                     
\
+                            ptrauth_string_discriminator(discriminatorString))
+#else
+#define PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(key, addressDiscriminated,       
\
+                                              discriminatorString)             
\
+    __ptrauth(key, addressDiscriminated,                                       
\
+              ptrauth_string_discriminator(discriminatorString))
+#endif
+#else
+#define PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(key, addressDiscriminated,       
\
+                                              discriminatorString)
+#endif
+
+// Helper wrappers for pointer auth qualifiers because we use a lot of variants
+// Suffixes:
+//  * PDC : ptrauth_key_process_dependent_code
+//  * RA  : ptrauth_key_return_address
+//  * FN  : ptrauth_key_function_pointer
+#define PERSONALITY_PTRAUTH_RI_FN(__discriminator)                             
\
+    PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_function_pointer,        
\
+                       /*__address_discriminated=*/1,                          
\
+                       __discriminator)
+#define PERSONALITY_PTRAUTH_RI_PDC(__discriminator)                            
\
+    PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_process_dependent_code,  
\
+                       /*__address_discriminated=*/1,                          
\
+                       __discriminator)
+#define PERSONALITY_PTRAUTH_RI_RA(__discriminator)                             
\
+    PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_return_address,          
\
+                       /*__address_discriminated=*/1,                          
\
+                       __discriminator)
+
 // Pointer encodings documented at:
 //   http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
 
@@ -205,7 +244,8 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
     return continueUnwind(exceptionObject, context);
 
   uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
-  uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
+  uintptr_t PERSONALITY_PTRAUTH_RI_FN("__gcc_personality_v0'funcStart")
+      funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
   uintptr_t pcOffset = pc - funcStart;
 
   // Parse LSDA header.
@@ -224,11 +264,14 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
   const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
   const uint8_t *p = callSiteTableStart;
   while (p < callSiteTableEnd) {
-    uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
-    size_t length = readEncodedPointer(&p, callSiteEncoding);
-    size_t landingPad = readEncodedPointer(&p, callSiteEncoding);
+    uintptr_t PERSONALITY_PTRAUTH_RI_PDC("__gcc_personality_v0'start")
+        start = readEncodedPointer(&p, callSiteEncoding);
+    size_t PERSONALITY_PTRAUTH_RI_PDC("__gcc_personality_v0'length")
+        length = readEncodedPointer(&p, callSiteEncoding);
+    size_t PERSONALITY_PTRAUTH_RI_PDC("__gcc_personality_v0'landingPadOffset")
+        landingPadOffset = readEncodedPointer(&p, callSiteEncoding);
     readULEB128(&p); // action value not used for C code
-    if (landingPad == 0)
+    if (landingPadOffset == 0)
       continue; // no landing pad for this entry
     if ((start <= pcOffset) && (pcOffset < (start + length))) {
       // Found landing pad for the PC.
@@ -238,7 +281,21 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
       _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
                     (uintptr_t)exceptionObject);
       _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
-      _Unwind_SetIP(context, (funcStart + landingPad));
+#define LANDING_PAD_DISCRIMINATOR "__gcc_personality_v0'landingPad"
+      size_t PERSONALITY_PTRAUTH_RI_RA(LANDING_PAD_DISCRIMINATOR)
+          landingPad = funcStart + landingPadOffset;
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+      uintptr_t stack_pointer = _Unwind_GetGR(context, -2);
+      const uintptr_t existingDiscriminator = ptrauth_blend_discriminator(
+          &landingPad,
+          ptrauth_string_discriminator(LANDING_PAD_DISCRIMINATOR));
+      uintptr_t newIP = (uintptr_t)ptrauth_auth_and_resign(
+          *(void **)&landingPad, ptrauth_key_function_pointer,
+          existingDiscriminator, ptrauth_key_return_address, stack_pointer);
+      _Unwind_SetIP(context, newIP);
+#else
+      _Unwind_SetIP(context, landingPad);
+#endif
       return _URC_INSTALL_CONTEXT;
     }
   }
diff --git a/compiler-rt/lib/profile/InstrProfilingValue.c 
b/compiler-rt/lib/profile/InstrProfilingValue.c
index a608d41d39e77..cd6ae3d7a4248 100644
--- a/compiler-rt/lib/profile/InstrProfilingValue.c
+++ b/compiler-rt/lib/profile/InstrProfilingValue.c
@@ -83,7 +83,13 @@ __llvm_profile_iterate_data(const __llvm_profile_data *Data) 
{
 /* This method is only used in value profiler mock testing.  */
 COMPILER_RT_VISIBILITY void *
 __llvm_get_function_addr(const __llvm_profile_data *Data) {
-  return Data->FunctionPointer;
+  void *FP = Data->FunctionPointer;
+#if __has_feature(ptrauth_calls)
+  // This is only used for tests where we compare against what happens to be
+  // signed pointers.
+  FP = ptrauth_sign_unauthenticated(FP, VALID_CODE_KEY, 0);
+#endif
+   return FP;
 }
 
 /* Allocate an array that holds the pointers to the linked lists of
diff --git a/libcxxabi/include/__cxxabi_config.h 
b/libcxxabi/include/__cxxabi_config.h
index 759445dac91f9..e67d065fe57f3 100644
--- a/libcxxabi/include/__cxxabi_config.h
+++ b/libcxxabi/include/__cxxabi_config.h
@@ -32,7 +32,8 @@
 #endif
 
 #if defined(_WIN32)
- #if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) || 
(defined(__MINGW32__) && !defined(_LIBCXXABI_BUILDING_LIBRARY))
+ #if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) ||                     
\
+     (defined(__MINGW32__) && !defined(_LIBCXXABI_BUILDING_LIBRARY))
   #define _LIBCXXABI_HIDDEN
   #define _LIBCXXABI_DATA_VIS
   #define _LIBCXXABI_FUNC_VIS
@@ -109,4 +110,49 @@
 #  define _LIBCXXABI_NOEXCEPT noexcept
 #endif
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+#  define _LIBCXXABI_PTRAUTH(__key, __address_discriminated, __discriminator)  
\
+    __ptrauth(__key,__address_discriminated,                                   
\
+              ptrauth_string_discriminator(__discriminator))
+// This work around is required to support divergence in spelling
+// during the ptrauth upstreaming process.
+#  if __has_feature(ptrauth_restricted_intptr_qualifier)
+#  define _LIBCXXABI_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated, 
\
+                                               __discriminator)                
\
+    __ptrauth_restricted_intptr(__key,__address_discriminated,                 
\
+                                ptrauth_string_discriminator(__discriminator))
+#  else
+#  define _LIBCXXABI_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated, 
\
+                                               __discriminator)                
\
+    __ptrauth(__key,__address_discriminated,                                   
\
+              ptrauth_string_discriminator(__discriminator))
+#  endif
+#else
+#  define _LIBCXXABI_PTRAUTH(__key, __address_discriminated, __discriminator)
+#  define _LIBCXXABI_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated, 
\
+                                               __discriminator)
+#endif
+
+// Helper wrappers for pointer auth qualifiers because we use a lot of variants
+// Suffixes:
+//  * _RI : qualifier is __ptrauth_restricted_intptr
+//  * PDD : key is ptrauth_key_process_dependent_data
+//  * FN  : key is ptrauth_key_function_pointer
+#define _LIBCXXABI_PTRAUTH_PDD(__discriminator)                                
\
+    _LIBCXXABI_PTRAUTH(ptrauth_key_process_dependent_data,                     
\
+                       /*__address_discriminated=*/1,                          
\
+                       __discriminator)
+#define _LIBCXXABI_PTRAUTH_FN(__discriminator)                                 
\
+    _LIBCXXABI_PTRAUTH(ptrauth_key_function_pointer,                           
\
+                       /*__address_discriminated=*/1,                          
\
+                       __discriminator)
+#define _LIBCXXABI_PTRAUTH_RI_PDD(__discriminator)                             
\
+    _LIBCXXABI_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_process_dependent_data,   
\
+                                         /*__address_discriminated=*/1,        
\
+                                         __discriminator)
+
 #endif // ____CXXABI_CONFIG_H
diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h
index aba08f2992103..4c69d48048f02 100644
--- a/libcxxabi/src/cxa_exception.h
+++ b/libcxxabi/src/cxa_exception.h
@@ -47,10 +47,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     // In Wasm, a destructor returns its argument
     void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
 #else
-    void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
+    void(_LIBCXXABI_DTOR_FUNC* 
_LIBCXXABI_PTRAUTH_FN("__cxa_exception::exceptionDestructor") 
exceptionDestructor)(void*);
 #endif
-    std::unexpected_handler unexpectedHandler;
-    std::terminate_handler  terminateHandler;
+    std::unexpected_handler 
_LIBCXXABI_PTRAUTH_FN("__cxa_exception::unexpectedHandler") unexpectedHandler;
+    std::terminate_handler 
_LIBCXXABI_PTRAUTH_FN("__cxa_exception::terminateHandler") terminateHandler;
 
     __cxa_exception *nextException;
 
@@ -61,10 +61,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-    const unsigned char *actionRecord;
-    const unsigned char *languageSpecificData;
-    void *catchTemp;
-    void *adjustedPtr;
+    const unsigned char* 
_LIBCXXABI_PTRAUTH_PDD("__cxa_exception::actionRecord") actionRecord;
+    const unsigned char* 
_LIBCXXABI_PTRAUTH_PDD("__cxa_exception::languageSpecificData") 
languageSpecificData;
+    void* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::catchTemp") catchTemp;
+    void* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::adjustedPtr") adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
@@ -79,6 +79,8 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
 // http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
 // The layout of this structure MUST match the layout of __cxa_exception, with
 // primaryException instead of referenceCount.
+// The tags used in the pointer authentication qualifiers also need to match
+// those of the corresponding members in __cxa_exception.
 struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
     void* reserve; // padding.
@@ -86,9 +88,9 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #endif
 
     std::type_info *exceptionType;
-    void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
-    std::unexpected_handler unexpectedHandler;
-    std::terminate_handler terminateHandler;
+    void(_LIBCXXABI_DTOR_FUNC* 
_LIBCXXABI_PTRAUTH_FN("__cxa_exception::exceptionDestructor") 
exceptionDestructor)(void*);
+    std::unexpected_handler 
_LIBCXXABI_PTRAUTH_FN("__cxa_exception::unexpectedHandler") unexpectedHandler;
+    std::terminate_handler 
_LIBCXXABI_PTRAUTH_FN("__cxa_exception::terminateHandler") terminateHandler;
 
     __cxa_exception *nextException;
 
@@ -99,10 +101,10 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-    const unsigned char *actionRecord;
-    const unsigned char *languageSpecificData;
-    void * catchTemp;
-    void *adjustedPtr;
+    const unsigned char* 
_LIBCXXABI_PTRAUTH_PDD("__cxa_exception::actionRecord") actionRecord;
+    const unsigned char* 
_LIBCXXABI_PTRAUTH_PDD("__cxa_exception::languageSpecificData") 
languageSpecificData;
+    void* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::catchTemp") catchTemp;
+    void* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::adjustedPtr") adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
diff --git a/libcxxabi/src/cxa_personality.cpp 
b/libcxxabi/src/cxa_personality.cpp
index 5f6e75c5be19c..cbb3f46e0f55c 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -22,6 +22,12 @@
 #include "private_typeinfo.h"
 #include "unwind.h"
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
+#include "libunwind.h"
+
 // TODO: This is a temporary workaround for libc++abi to recognize that it's 
being
 // built against LLVM's libunwind. LLVM's libunwind started reporting 
_LIBUNWIND_VERSION
 // in LLVM 15 -- we can remove this workaround after shipping LLVM 17. Once we 
remove
@@ -527,12 +533,19 @@ get_thrown_object_ptr(_Unwind_Exception* unwind_exception)
 namespace
 {
 
+#define _LIBCXXABI_PTRAUTH_KEY ptrauth_key_process_dependent_code
+typedef const uint8_t* 
_LIBCXXABI_PTRAUTH_PDD("scan_results::languageSpecificData") lsd_ptr_t;
+typedef const uint8_t* _LIBCXXABI_PTRAUTH_PDD("scan_results::actionRecord") 
action_ptr_t;
+#define _LIBCXXABI_PTRAUTH_SCANRESULT_LANDINGPAD_DISC 
"scan_results::landingPad"
+typedef uintptr_t 
_LIBCXXABI_PTRAUTH_RI_PDD(_LIBCXXABI_PTRAUTH_SCANRESULT_LANDINGPAD_DISC) 
landing_pad_t;
+typedef void* 
_LIBCXXABI_PTRAUTH_PDD(_LIBCXXABI_PTRAUTH_SCANRESULT_LANDINGPAD_DISC) 
landing_pad_ptr_t;
+
 struct scan_results
 {
     int64_t        ttypeIndex;   // > 0 catch handler, < 0 exception spec 
handler, == 0 a cleanup
-    const uint8_t* actionRecord;         // Currently unused.  Retained to 
ease future maintenance.
-    const uint8_t* languageSpecificData;  // Needed only for 
__cxa_call_unexpected
-    uintptr_t      landingPad;   // null -> nothing found, else something found
+    action_ptr_t actionRecord;   // Currently unused.  Retained to ease future 
maintenance.
+    lsd_ptr_t languageSpecificData; // Needed only for __cxa_call_unexpected
+    landing_pad_t landingPad;       // null -> nothing found, else something 
found
     void*          adjustedPtr;  // Used in cxa_exception.cpp
     _Unwind_Reason_Code reason;  // One of _URC_FATAL_PHASE1_ERROR,
                                  //        _URC_FATAL_PHASE2_ERROR,
@@ -541,7 +554,33 @@ struct scan_results
 };
 
 }  // unnamed namespace
+}
 
+namespace {
+// The logical model for casting authenticated function pointers makes
+// it impossible to directly cast them without breaking the authentication,
+// as a result we need this pair of helpers.
+template <typename PtrType>
+void set_landing_pad_as_ptr(scan_results& results, const PtrType& out) {
+  union {
+    landing_pad_t* as_landing_pad;
+    landing_pad_ptr_t* as_pointer;
+  } u;
+  u.as_landing_pad = &results.landingPad;
+  *u.as_pointer = out;
+}
+
+static const landing_pad_ptr_t& get_landing_pad_as_ptr(const scan_results& 
results) {
+  union {
+    const landing_pad_t* as_landing_pad;
+    const landing_pad_ptr_t* as_pointer;
+  } u;
+  u.as_landing_pad = &results.landingPad;
+  return *u.as_pointer;
+}
+} // unnamed namespace
+
+extern "C" {
 static
 void
 set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
@@ -557,7 +596,22 @@ set_registers(_Unwind_Exception* unwind_exception, 
_Unwind_Context* context,
                 reinterpret_cast<uintptr_t>(unwind_exception));
   _Unwind_SetGR(context, __builtin_eh_return_data_regno(1),
                 static_cast<uintptr_t>(results.ttypeIndex));
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+  auto stack_pointer = _Unwind_GetGR(context, UNW_REG_SP);
+  // We manually re-sign the IP as the __ptrauth qualifiers cannot
+  // express the required relationship with the destination address
+  const auto existingDiscriminator = ptrauth_blend_discriminator(
+      &results.landingPad,
+      
ptrauth_string_discriminator(_LIBCXXABI_PTRAUTH_SCANRESULT_LANDINGPAD_DISC));
+  unw_word_t newIP = 
(unw_word_t)ptrauth_auth_and_resign(*(void**)&results.landingPad,
+                                                         
_LIBCXXABI_PTRAUTH_KEY,
+                                                         existingDiscriminator,
+                                                         
ptrauth_key_return_address,
+                                                         stack_pointer);
+  _Unwind_SetIP(context, newIP);
+#else
   _Unwind_SetIP(context, results.landingPad);
+#endif
 }
 
 /*
@@ -691,12 +745,12 @@ static void scan_eh_tab(scan_results &results, 
_Unwind_Action actions,
         // The call sites are ordered in increasing value of start
         uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
         uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
-        uintptr_t landingPad = readEncodedPointer(&callSitePtr, 
callSiteEncoding);
+        landing_pad_t landingPad = readEncodedPointer(&callSitePtr, 
callSiteEncoding);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if ((start <= ipOffset) && (ipOffset < (start + length)))
 #else  // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__
         // ip is 1-based index into this table
-        uintptr_t landingPad = readULEB128(&callSitePtr);
+        landing_pad_t landingPad = readULEB128(&callSitePtr);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if (--ip == 0)
 #endif // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__
@@ -935,8 +989,7 @@ __gxx_personality_v0
         results.ttypeIndex = exception_header->handlerSwitchValue;
         results.actionRecord = exception_header->actionRecord;
         results.languageSpecificData = exception_header->languageSpecificData;
-        results.landingPad =
-            reinterpret_cast<uintptr_t>(exception_header->catchTemp);
+        set_landing_pad_as_ptr(results, exception_header->catchTemp);
         results.adjustedPtr = exception_header->adjustedPtr;
 
         // Jump to the handler.
@@ -970,7 +1023,7 @@ __gxx_personality_v0
             exc->handlerSwitchValue = static_cast<int>(results.ttypeIndex);
             exc->actionRecord = results.actionRecord;
             exc->languageSpecificData = results.languageSpecificData;
-            exc->catchTemp = reinterpret_cast<void*>(results.landingPad);
+            exc->catchTemp = get_landing_pad_as_ptr(results);
             exc->adjustedPtr = results.adjustedPtr;
 #ifdef __WASM_EXCEPTIONS__
             // Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index b2dae8feed9a3..e7375bbca1b3d 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -43,6 +43,61 @@
   #define LIBUNWIND_AVAIL
 #endif
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+#define _LIBUNWIND_PTRAUTH(__key, __address_discriminated, __discriminator)    
\
+  __ptrauth(__key, __address_discriminated,                                    
\
+            ptrauth_string_discriminator(__discriminator))
+// This work around is required to support divergence in spelling
+// developed during the ptrauth upstreaming process.
+#if __has_feature(ptrauth_restricted_intptr_qualifier)
+#define _LIBUNWIND_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated,   
\
+                                             __discriminator)                  
\
+  __ptrauth_restricted_intptr(__key, __address_discriminated,                  
\
+             ptrauth_string_discriminator(__discriminator))
+#else
+#define _LIBUNWIND_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated,   
\
+                                             __discriminator)                  
\
+  __ptrauth(__key, __address_discriminated,                                    
\
+             ptrauth_string_discriminator(__discriminator))
+#endif
+#else
+#define _LIBUNWIND_PTRAUTH(__key, __address_discriminated, __discriminator)
+#define _LIBUNWIND_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated,   
\
+                                             __discriminator)
+#endif
+
+// Helper wrappers for pointer auth qualifiers because we use a lot of variants
+// Suffixes:
+//  * RI_*: __ptrauth_restricted_intptr
+//  * PDD : ptrauth_key_process_dependent_data
+//  * PIC : ptrauth_key_process_independent_code
+//  * PDC : ptrauth_key_process_dependent_code
+//  * FN  : ptrauth_key_function_pointer
+#define __LIBUNWIND_PTRAUTH_RI_PDD(__discriminator)                            
\
+    _LIBUNWIND_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_process_dependent_data,   
\
+                                         /*__address_discriminated=*/1,        
\
+                                         __discriminator)
+#define __LIBUNWIND_PTRAUTH_RI_PIC(__discriminator)                            
\
+    _LIBUNWIND_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_process_independent_code, 
\
+                                         /*__address_discriminated=*/1,        
\
+                                         __discriminator)
+#define __LIBUNWIND_PTRAUTH_RI_PDC(__discriminator)                            
\
+    _LIBUNWIND_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_process_dependent_code,   
\
+                                         /*__address_discriminated=*/1,        
\
+                                         __discriminator)
+#define __LIBUNWIND_PTRAUTH_RI_FN(__discriminator)                             
\
+    _LIBUNWIND_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_function_pointer,         
\
+                                         /*__address_discriminated=*/1,        
\
+                                         __discriminator)
+#define __LIBUNWIND_PTRAUTH_FN(__discriminator)                                
\
+    _LIBUNWIND_PTRAUTH(ptrauth_key_function_pointer,                           
\
+                       /*__address_discriminated=*/1,                          
\
+                       __discriminator)
+
 #if defined(_WIN32) && defined(__SEH__)
   #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR __attribute__((__aligned__(16)))
 #else
@@ -88,17 +143,24 @@ typedef double unw_fpreg_t;
 #endif
 
 struct unw_proc_info_t {
-  unw_word_t  start_ip;         /* start address of function */
-  unw_word_t  end_ip;           /* address after end of function */
-  unw_word_t  lsda;             /* address of language specific data area, */
-                                /*  or zero if not used */
-  unw_word_t  handler;          /* personality routine, or zero if not used */
+  unw_word_t __LIBUNWIND_PTRAUTH_RI_PIC("unw_proc_info_t::start_ip")
+          start_ip;             /* start address of function */
+  unw_word_t __LIBUNWIND_PTRAUTH_RI_PIC("unw_proc_info_t::end_ip")
+          end_ip;               /* address after end of function */
+  unw_word_t __LIBUNWIND_PTRAUTH_RI_PDD("unw_proc_info_t::lsda")
+          lsda;                 /* address of language specific data area, */
+                                /* or zero if not used */
+  unw_word_t __LIBUNWIND_PTRAUTH_RI_FN("unw_proc_info_t::handler")
+          handler;              /* personality routine, or zero if not used */
   unw_word_t  gp;               /* not used */
-  unw_word_t  flags;            /* not used */
+  unw_word_t __LIBUNWIND_PTRAUTH_RI_PDD("unw_proc_info_t::flags") \
+          flags;                /* not used */
   uint32_t    format;           /* compact unwind encoding, or zero if none */
   uint32_t    unwind_info_size; /* size of DWARF unwind info, or zero if none 
*/
-  unw_word_t  unwind_info;      /* address of DWARF unwind info, or zero */
-  unw_word_t  extra;            /* mach_header of mach-o image containing func 
*/
+  unw_word_t __LIBUNWIND_PTRAUTH_RI_PDD("unw_proc_info_t::unwind_info")
+          unwind_info;          /* address of DWARF unwind info, or zero */
+  unw_word_t __LIBUNWIND_PTRAUTH_RI_PDD("unw_proc_info_t::extra")
+          extra;                /* mach_header of mach-o image containing func 
*/
 };
 typedef struct unw_proc_info_t unw_proc_info_t;
 
diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp
index 5551c7d4bef1c..1b89d5c0386d8 100644
--- a/libunwind/src/AddressSpace.hpp
+++ b/libunwind/src/AddressSpace.hpp
@@ -129,26 +129,36 @@ struct UnwindInfoSections {
     defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) ||                              
\
     defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
   // No dso_base for SEH.
-  uintptr_t       dso_base;
+  uintptr_t __LIBUNWIND_PTRAUTH_RI_PDD("UnwindInfoSections::dso_base")
+      dso_base = 0;
 #endif
 #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
-  size_t          text_segment_length;
+  size_t __LIBUNWIND_PTRAUTH_RI_PDD("UnwindInfoSections::text_segment_length")
+      text_segment_length = 0;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
-  uintptr_t       dwarf_section;
-  size_t          dwarf_section_length;
+  uintptr_t __LIBUNWIND_PTRAUTH_RI_PDD("UnwindInfoSections::dwarf_section")
+      dwarf_section = 0;
+  size_t __LIBUNWIND_PTRAUTH_RI_PDD("UnwindInfoSections::dwarf_section_length")
+      dwarf_section_length = 0;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
-  uintptr_t       dwarf_index_section;
-  size_t          dwarf_index_section_length;
+  uintptr_t 
__LIBUNWIND_PTRAUTH_RI_PDD("UnwindInfoSections::dwarf_index_section")
+      dwarf_index_section = 0;
+  size_t 
__LIBUNWIND_PTRAUTH_RI_PDD("UnwindInfoSections::dwarf_index_section_length")
+      dwarf_index_section_length = 0;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
-  uintptr_t       compact_unwind_section;
-  size_t          compact_unwind_section_length;
+  uintptr_t 
__LIBUNWIND_PTRAUTH_RI_PDD("UnwindInfoSections::compact_unwind_section")
+      compact_unwind_section = 0;
+  size_t 
__LIBUNWIND_PTRAUTH_RI_PDD("UnwindInfoSections::compact_unwind_section_length")
+      compact_unwind_section_length = 0;
 #endif
 #if defined(_LIBUNWIND_ARM_EHABI)
-  uintptr_t       arm_section;
-  size_t          arm_section_length;
+  uintptr_t __LIBUNWIND_PTRAUTH_RI_PDD("UnwindInfoSections::arm_section")
+      arm_section = 0;
+  size_t __LIBUNWIND_PTRAUTH_RI_PDD("UnwindInfoSections::arm_section_length")
+      arm_section_length = 0;
 #endif
 };
 
@@ -196,7 +206,7 @@ class _LIBUNWIND_HIDDEN LocalAddressSpace {
   static int64_t  getSLEB128(pint_t &addr, pint_t end);
 
   pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
-                     pint_t datarelBase = 0);
+                     pint_t datarelBase = 0, pint_t *resultAddr = nullptr);
   bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
                         unw_word_t *offset);
   bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
@@ -269,7 +279,7 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, 
pint_t end) {
 
 inline LocalAddressSpace::pint_t
 LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
-                               pint_t datarelBase) {
+                               pint_t datarelBase, pint_t *resultAddr) {
   pint_t startAddr = addr;
   const uint8_t *p = (uint8_t *)addr;
   pint_t result;
@@ -353,8 +363,14 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, 
uint8_t encoding,
     break;
   }
 
-  if (encoding & DW_EH_PE_indirect)
-    result = getP(result);
+  if (encoding & DW_EH_PE_indirect) {
+    if (resultAddr)
+      *resultAddr = result;
+     result = getP(result);
+  } else {
+    if (resultAddr)
+      *resultAddr = startAddr;
+  }
 
   return result;
 }
diff --git a/libunwind/src/DwarfInstructions.hpp 
b/libunwind/src/DwarfInstructions.hpp
index e7be0d6d5d635..3c34ebb6b7a16 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -22,6 +22,9 @@
 #include "dwarf2.h"
 #include "libunwind_ext.h"
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
 
 namespace libunwind {
 
@@ -34,8 +37,9 @@ class DwarfInstructions {
   typedef typename A::pint_t pint_t;
   typedef typename A::sint_t sint_t;
 
-  static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
-                           R &registers, bool &isSignalFrame, bool stage2);
+  static int stepWithDwarf(A &addressSpace, typename R::link_reg_t &pc,
+                           pint_t fdeStart, R &registers, bool &isSignalFrame,
+                           bool stage2);
 
 private:
 
@@ -207,7 +211,8 @@ bool DwarfInstructions<A, R>::isReturnAddressSignedWithPC(A 
&addressSpace,
 #endif
 
 template <typename A, typename R>
-int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
+int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace,
+                                           typename R::link_reg_t &pc,
                                            pint_t fdeStart, R &registers,
                                            bool &isSignalFrame, bool stage2) {
   FDE_Info fdeInfo;
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 7e85025dd054d..8cde9cfe0e6e2 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -23,6 +23,10 @@
 
 #include "config.h"
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
 namespace libunwind {
 
 /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
@@ -33,6 +37,7 @@ template <typename A>
 class CFI_Parser {
 public:
   typedef typename A::pint_t pint_t;
+  typedef pint_t __LIBUNWIND_PTRAUTH_RI_FN("CIE_Info::personality") 
personality_t;
 
   /// Information encoded in a CIE (Common Information Entry)
   struct CIE_Info {
@@ -43,7 +48,7 @@ class CFI_Parser {
     uint8_t   lsdaEncoding;
     uint8_t   personalityEncoding;
     uint8_t   personalityOffsetInCIE;
-    pint_t    personality;
+    personality_t personality;
     uint32_t  codeAlignFactor;
     int       dataAlignFactor;
     bool      isSignalFrame;
@@ -313,6 +318,17 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, 
pint_t ehSectionStart,
   }
   return false;
 }
+namespace {
+// This helper function handles setting the manually signed personality on
+// CIE_Info without attempt to authenticate and/or re-sign
+template <typename CIE_Info, typename T>
+void set_cie_info_personality(CIE_Info *info, T signed_personality) {
+  static_assert(sizeof(info->personality) == sizeof(signed_personality),
+                "Signed personality is the wrong size");
+  memmove((void *)&info->personality, (void *)&signed_personality,
+          sizeof(signed_personality));
+}
+}
 
 /// Extract info from a CIE
 template <typename A>
@@ -369,6 +385,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t 
cie,
   cieInfo->returnAddressRegister = (uint8_t)raReg;
   // parse augmentation data based on augmentation string
   const char *result = NULL;
+  pint_t resultAddr = 0;
   if (addressSpace.get8(strStart) == 'z') {
     // parse augmentation data length
     addressSpace.getULEB128(p, cieContentEnd);
@@ -377,13 +394,32 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, 
pint_t cie,
       case 'z':
         cieInfo->fdesHaveAugmentationData = true;
         break;
-      case 'P':
+      case 'P': {
         cieInfo->personalityEncoding = addressSpace.get8(p);
         ++p;
         cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
-        cieInfo->personality = addressSpace
-            .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
+        pint_t personality = addressSpace.getEncodedP(
+            p, cieContentEnd, cieInfo->personalityEncoding,
+            /*datarelBase=*/0, &resultAddr);
+#if __has_feature(ptrauth_calls)
+        if (personality) {
+          // The GOT for the personality function was signed address
+          // authenticated. Manually re-sign with the CIE_Info::personality
+          // schema. If we could guarantee the encoding of the personality we
+          // could avoid this by simply giving resultAddr the correct ptrauth
+          // schema and performing an assignment.
+          const auto discriminator = ptrauth_blend_discriminator(
+              &cieInfo->personality,
+              ptrauth_string_discriminator("CIE_Info::personality"));
+          void *signedPtr = ptrauth_auth_and_resign(
+              (void *)personality, ptrauth_key_function_pointer, resultAddr,
+              ptrauth_key_function_pointer, discriminator);
+          personality = (pint_t)signedPtr;
+        }
+#endif
+        set_cie_info_personality(cieInfo, personality);
         break;
+      }
       case 'L':
         cieInfo->lsdaEncoding = addressSpace.get8(p);
         ++p;
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index 2c3bfb7e8428a..8d43453329af5 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -18,6 +18,11 @@
 #include "config.h"
 #include "libunwind.h"
 #include "shadow_stack_unwind.h"
+#include "libunwind_ext.h"
+
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
 
 namespace libunwind {
 
@@ -93,6 +98,13 @@ class _LIBUNWIND_HIDDEN Registers_x86 {
   uint32_t  getEDI() const         { return _registers.__edi; }
   void      setEDI(uint32_t value) { _registers.__edi = value; }
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+  void      loadAndAuthenticateLinkRegister(reg_t srcLinkRegister,
+                                       link_reg_t *dstLinkRegister) {
+    *dstLinkRegister = srcLinkRegister;
+  }
+
 private:
   struct GPRs {
     unsigned int __eax;
@@ -311,6 +323,13 @@ class _LIBUNWIND_HIDDEN Registers_x86_64 {
   uint64_t  getR15() const         { return _registers.__r15; }
   void      setR15(uint64_t value) { _registers.__r15 = value; }
 
+  typedef uint64_t reg_t;
+  typedef uint64_t link_reg_t;
+  void      loadAndAuthenticateLinkRegister(reg_t srcLinkRegister,
+                                       link_reg_t *dstLinkRegister) {
+    *dstLinkRegister = srcLinkRegister;
+  }
+
 private:
   struct GPRs {
     uint64_t __rax;
@@ -622,6 +641,13 @@ class _LIBUNWIND_HIDDEN Registers_ppc {
   uint64_t  getLR() const         { return _registers.__lr; }
   void      setLR(uint32_t value) { _registers.__lr = value; }
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+  void      loadAndAuthenticateLinkRegister(reg_t srcLinkRegister,
+                                       link_reg_t *dstLinkRegister) {
+    *dstLinkRegister = srcLinkRegister;
+  }
+
 private:
   struct ppc_thread_state_t {
     unsigned int __srr0; /* Instruction address register (PC) */
@@ -1845,10 +1871,59 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
 
   uint64_t  getSP() const         { return _registers.__sp; }
   void      setSP(uint64_t value) { _registers.__sp = value; }
-  uint64_t  getIP() const         { return _registers.__pc; }
-  void      setIP(uint64_t value) { _registers.__pc = value; }
-  uint64_t  getFP() const         { return _registers.__fp; }
-  void      setFP(uint64_t value) { _registers.__fp = value; }
+  uint64_t  getIP() const         {
+    uint64_t value = _registers.__pc;
+#if __has_feature(ptrauth_calls)
+    // Note the value of the PC was signed to its address in the register state
+    // but everyone else expects it to be sign by the SP, so convert on return.
+    value = (uint64_t)ptrauth_auth_and_resign((void *)_registers.__pc,
+                                              ptrauth_key_return_address,
+                                              &_registers.__pc,
+                                              ptrauth_key_return_address,
+                                              getSP());
+#endif
+    return value;
+  }
+  void      setIP(uint64_t value) {
+#if __has_feature(ptrauth_calls)
+    // Note the value which was set should have been signed with the SP.
+    // We then resign with the slot we are being stored in to so that both SP
+    // and LR can't be spoofed at the same time.
+    value = (uint64_t)ptrauth_auth_and_resign((void *)value,
+                                              ptrauth_key_return_address,
+                                              getSP(),
+                                              ptrauth_key_return_address,
+                                              &_registers.__pc);
+#endif
+    _registers.__pc = value;
+  }
+  uint64_t  getFP() const         {
+    return _registers.__fp;
+  }
+  void      setFP(uint64_t value) {
+    _registers.__fp = value;
+  }
+
+  typedef uint64_t reg_t;
+  typedef uint64_t __LIBUNWIND_PTRAUTH_RI_PDC("Registers_arm64::link_reg_t") 
link_reg_t;
+  void
+  loadAndAuthenticateLinkRegister(reg_t inplaceAuthedLinkRegister,
+                                  link_reg_t *referenceAuthedLinkRegister) {
+#if __has_feature(ptrauth_calls)
+    // If we are in an arm64e frame, then the PC should have been signed
+    // with the SP
+    *referenceAuthedLinkRegister =
+      (uint64_t)ptrauth_auth_data((void *)inplaceAuthedLinkRegister, 
ptrauth_key_return_address, _registers.__sp);
+#else
+    *referenceAuthedLinkRegister = inplaceAuthedLinkRegister;
+#endif
+  }
+
+  // arm64_32 and i386 simulator hack
+  void      loadAndAuthenticateLinkRegister(uint32_t srcLinkRegister,
+                                            uint32_t *dstLinkRegister) {
+    *dstLinkRegister = srcLinkRegister;
+  }
 
 private:
   struct GPRs {
@@ -1877,6 +1952,29 @@ inline Registers_arm64::Registers_arm64(const void 
*registers) {
   memcpy(_vectorHalfRegisters,
          static_cast<const uint8_t *>(registers) + sizeof(GPRs),
          sizeof(_vectorHalfRegisters));
+#if __has_feature(ptrauth_calls)
+  uint64_t pcRegister = 0;
+  memcpy(&pcRegister, ((uint8_t*)&_registers) + offsetof(GPRs, __pc), 
sizeof(pcRegister));
+  setIP(pcRegister);
+  uint64_t fpRegister = 0;
+  memcpy(&fpRegister, ((uint8_t*)&_registers) + offsetof(GPRs, __fp), 
sizeof(fpRegister));
+  setFP(fpRegister);
+#endif
+}
+
+inline Registers_arm64::Registers_arm64(const Registers_arm64& other) {
+  *this = other;
+}
+
+inline Registers_arm64& Registers_arm64::operator=(const Registers_arm64& 
other) {
+  memcpy(&_registers, &other._registers, sizeof(_registers));
+  memcpy(_vectorHalfRegisters, &other._vectorHalfRegisters,
+         sizeof(_vectorHalfRegisters));
+#if __has_feature(ptrauth_calls)
+  setIP(other.getIP());
+  setFP(other.getFP());
+#endif
+  return *this;
 }
 
 inline Registers_arm64::Registers_arm64() {
@@ -2140,6 +2238,13 @@ class _LIBUNWIND_HIDDEN Registers_arm {
   uint32_t  getIP() const         { return _registers.__pc; }
   void      setIP(uint32_t value) { _registers.__pc = value; }
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+  void      loadAndAuthenticateLinkRegister(reg_t srcLinkRegister,
+                                       link_reg_t *dstLinkRegister) {
+    *dstLinkRegister = srcLinkRegister;
+  }
+
   void saveVFPAsX() {
     assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15);
     _use_X_for_vfp_save = true;
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 55db035e62040..feae9263df882 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -111,6 +111,10 @@ extern "C" _Unwind_Reason_Code __libunwind_seh_personality(
 
 #endif
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
 namespace libunwind {
 
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
@@ -1046,18 +1050,22 @@ class UnwindCursor : public AbstractUnwindCursor{
   bool getInfoFromFdeCie(const typename CFI_Parser<A>::FDE_Info &fdeInfo,
                          const typename CFI_Parser<A>::CIE_Info &cieInfo,
                          pint_t pc, uintptr_t dso_base);
-  bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections &sects,
-                                            uint32_t fdeSectionOffsetHint=0);
+  bool getInfoFromDwarfSection(const typename R::link_reg_t &pc,
+                               const UnwindInfoSections &sects,
+                               uint32_t fdeSectionOffsetHint = 0);
   int stepWithDwarfFDE(bool stage2) {
+    typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
+    typename R::link_reg_t pc;
+    _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
     return DwarfInstructions<A, R>::stepWithDwarf(
-        _addressSpace, (pint_t)this->getReg(UNW_REG_IP),
-        (pint_t)_info.unwind_info, _registers, _isSignalFrame, stage2);
+        _addressSpace, pc, (pint_t)_info.unwind_info, _registers,
+        _isSignalFrame, stage2);
   }
 #endif
 
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
-  bool getInfoFromCompactEncodingSection(pint_t pc,
-                                            const UnwindInfoSections &sects);
+  bool getInfoFromCompactEncodingSection(const typename R::link_reg_t &pc,
+                                         const UnwindInfoSections &sects);
   int stepWithCompactEncoding(bool stage2 = false) {
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
     if ( compactSaysUseDwarf() )
@@ -1682,9 +1690,9 @@ bool UnwindCursor<A, R>::getInfoFromFdeCie(
 }
 
 template <typename A, typename R>
-bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
-                                                const UnwindInfoSections 
&sects,
-                                                uint32_t fdeSectionOffsetHint) 
{
+bool UnwindCursor<A, R>::getInfoFromDwarfSection(
+    const typename R::link_reg_t &pc, const UnwindInfoSections &sects,
+    uint32_t fdeSectionOffsetHint) {
   typename CFI_Parser<A>::FDE_Info fdeInfo;
   typename CFI_Parser<A>::CIE_Info cieInfo;
   bool foundFDE = false;
@@ -1741,9 +1749,21 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t 
pc,
 
 
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+// This helper function handles setting the manually signed handler on
+// unw_proc_info without attempt to authenticate and/or re-sign
+namespace {
+template <typename T>
+void set_proc_info_handler(unw_proc_info_t &info, T signed_handler) {
+  static_assert(sizeof(info.handler) == sizeof(signed_handler),
+                "Signed handler is the wrong size");
+  memmove((void *)&info.handler, (void *)&signed_handler,
+          sizeof(signed_handler));
+}
+} // unnamed namespace
+
 template <typename A, typename R>
-bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
-                                              const UnwindInfoSections &sects) 
{
+bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
+    const typename R::link_reg_t &pc, const UnwindInfoSections &sects) {
   const bool log = false;
   if (log)
     fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, 
mh=0x%llX)\n",
@@ -1974,6 +1994,17 @@ bool UnwindCursor<A, 
R>::getInfoFromCompactEncodingSection(pint_t pc,
         personalityIndex * sizeof(uint32_t));
     pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta;
     personality = _addressSpace.getP(personalityPointer);
+#if __has_feature(ptrauth_calls)
+    // The GOT for the personality function was signed address authenticated.
+    // Resign is as a regular function pointer.
+    const auto discriminator = ptrauth_blend_discriminator(
+        &_info.handler,
+        ptrauth_string_discriminator("unw_proc_info_t::handler"));
+    void *signedPtr = ptrauth_auth_and_resign(
+        (void *)personality, ptrauth_key_function_pointer, personalityPointer,
+        ptrauth_key_function_pointer, discriminator);
+    personality = (__typeof(personality))signedPtr;
+#endif
     if (log)
       fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), "
                       "personalityDelta=0x%08X, personality=0x%08llX\n",
@@ -1987,7 +2018,7 @@ bool UnwindCursor<A, 
R>::getInfoFromCompactEncodingSection(pint_t pc,
   _info.start_ip = funcStart;
   _info.end_ip = funcEnd;
   _info.lsda = lsda;
-  _info.handler = personality;
+  set_proc_info_handler(_info, personality);
   _info.gp = 0;
   _info.flags = 0;
   _info.format = encoding;
@@ -2640,13 +2671,17 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool 
isReturnAddress) {
   _isSigReturn = false;
 #endif
 
-  pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+  typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
+
 #if defined(_LIBUNWIND_ARM_EHABI)
   // Remove the thumb bit so the IP represents the actual instruction address.
   // This matches the behaviour of _Unwind_GetIP on arm.
-  pc &= (pint_t)~0x1;
+  rawPC &= (pint_t)~0x1;
 #endif
 
+  typename R::link_reg_t pc;
+  _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
+
   // Exit early if at the top of the stack.
   if (pc == 0) {
     _unwindInfoMissing = true;
@@ -3195,9 +3230,12 @@ void UnwindCursor<A, R>::getInfo(unw_proc_info_t *info) {
 
 template <typename A, typename R>
 bool UnwindCursor<A, R>::getFunctionName(char *buf, size_t bufLen,
-                                                           unw_word_t *offset) 
{
-  return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP),
-                                         buf, bufLen, offset);
+                                         unw_word_t *offset) {
+  typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
+  typename R::link_reg_t pc;
+  _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
+
+  return _addressSpace.findFunctionName(pc, buf, bufLen, offset);
 }
 
 #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index a258a832a9c31..7068e42c3d24b 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -31,6 +31,10 @@
 #include "shadow_stack_unwind.h"
 #include "unwind.h"
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
 #if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) &&   
\
     !defined(__wasm__)
 
@@ -90,6 +94,19 @@
   } while (0)
 #endif
 
+// There is not currently a clean way to cast between an authenticated
+// integer and an authenticated function pointer, so we need this helper
+// function to keep things clean.
+static _Unwind_Personality_Fn get_handler_function(unw_proc_info_t *frameInfo) 
{
+  union {
+    void *opaque_handler;
+    _Unwind_Personality_Fn __LIBUNWIND_PTRAUTH_FN("unw_proc_info_t::handler") *
+        handler;
+  } u;
+  u.opaque_handler = (void *)&frameInfo->handler;
+  return *u.handler;
+}
+
 static _Unwind_Reason_Code
 unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception 
*exception_object) {
   __unw_init_local(cursor, uc);
@@ -147,8 +164,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, 
_Unwind_Exception *except
     // If there is a personality routine, ask it if it will want to stop at
     // this frame.
     if (frameInfo.handler != 0) {
-      _Unwind_Personality_Fn p =
-          (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
+      _Unwind_Personality_Fn p = get_handler_function(&frameInfo);
       _LIBUNWIND_TRACE_UNWINDING(
           "unwind_phase1(ex_obj=%p): calling personality function %p",
           (void *)exception_object, (void *)(uintptr_t)p);
@@ -275,8 +291,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, 
_Unwind_Exception *except
     ++framesWalked;
     // If there is a personality routine, tell it we are unwinding.
     if (frameInfo.handler != 0) {
-      _Unwind_Personality_Fn p =
-          (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
+      _Unwind_Personality_Fn p = get_handler_function(&frameInfo);
       _Unwind_Action action = _UA_CLEANUP_PHASE;
       if (sp == exception_object->private_2) {
         // Tell personality this was the frame it marked in phase 1.
@@ -393,8 +408,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t 
*cursor,
     ++framesWalked;
     // If there is a personality routine, tell it we are unwinding.
     if (frameInfo.handler != 0) {
-      _Unwind_Personality_Fn p =
-          (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler);
+      _Unwind_Personality_Fn p = get_handler_function(&frameInfo);
       _LIBUNWIND_TRACE_UNWINDING(
           "unwind_phase2_forced(ex_obj=%p): calling personality function %p",
           (void *)exception_object, (void *)(uintptr_t)p);
@@ -597,6 +611,16 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct 
_Unwind_Context *context) {
   unw_cursor_t *cursor = (unw_cursor_t *)context;
   unw_word_t result;
   __unw_get_reg(cursor, UNW_REG_IP, &result);
+
+#if __has_feature(ptrauth_calls)
+    // If we are in an arm64e frame, then the PC should have been signed with 
the sp
+    {
+        unw_word_t sp;
+        __unw_get_reg(cursor, UNW_REG_SP, &sp);
+        result = (unw_word_t)ptrauth_auth_data((void*)result, 
ptrauth_key_return_address, sp);
+    }
+#endif
+
   _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
                        (void *)context, result);
   return (uintptr_t)result;
diff --git a/libunwind/src/UnwindRegistersSave.S 
b/libunwind/src/UnwindRegistersSave.S
index 5139a551ad245..74c5301674abc 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -767,6 +767,11 @@ LnoR2Fix:
 //
   .p2align 2
 DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+
+#if __has_feature(ptrauth_calls)
+  pacibsp
+#endif
+
   stp    x0, x1,  [x0, #0x000]
   stp    x2, x3,  [x0, #0x010]
   stp    x4, x5,  [x0, #0x020]
@@ -807,7 +812,12 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   str    d31,     [x0, #0x208]
 #endif
   mov    x0, #0                   // return UNW_ESUCCESS
+
+#if __has_feature(ptrauth_calls)
+  retab
+#else
   ret
+#endif
 
 #elif defined(__arm__) && !defined(__APPLE__)
 
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index cf39ec5f7dbdf..fc31566745143 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -16,6 +16,10 @@
 
 #include <stdlib.h>
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
 // Define the __has_feature extension for compilers that do not support it so
 // that we can later check for the presence of ASan in a compiler-neutral way.
 #if !defined(__has_feature)
@@ -126,6 +130,36 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, 
unw_regnum_t regNum,
       // First, get the FDE for the old location and then update it.
       co->getInfo(&info);
       co->setInfoBasedOnIPRegister(false);
+
+#if __has_feature(ptrauth_calls)
+      // It is only valid to set the IP within the current function.
+      // This is important for ptrauth, otherwise the IP cannot be correctly
+      // signed.
+      unw_word_t stripped_value =
+          (unw_word_t)ptrauth_strip((void *)value, ptrauth_key_return_address);
+      (void)stripped_value;
+      assert(stripped_value >= info.start_ip && stripped_value <= info.end_ip);
+#endif
+
+      pint_t sp = (pint_t)co->getReg(UNW_REG_SP);
+
+#if __has_feature(ptrauth_calls)
+      {
+        // PC should have been signed with the sp, so we verify that
+        // roundtripping does not fail.
+        pint_t pc = (pint_t)co->getReg(UNW_REG_IP);
+        if (ptrauth_auth_and_resign((void *)pc, ptrauth_key_return_address, sp,
+                                    ptrauth_key_return_address,
+                                    sp) != (void *)pc) {
+          _LIBUNWIND_LOG("Bad unwind through arm64e (0x%llX, 
0x%llX)->0x%llX\n",
+                         pc, sp,
+                         (pint_t)ptrauth_auth_data(
+                             (void *)pc, ptrauth_key_return_address, sp));
+          _LIBUNWIND_ABORT("Bad unwind through arm64e");
+        }
+      }
+#endif
+
       // If the original call expects stack adjustment, perform this now.
       // Normal frame unwinding would have included the offset already in the
       // CFA computation.

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to