[libunwind] [libunwind][AArch64] Protect PC within libunwind's context. (PR #113368)
Anton Korobeynikov via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 4 13:43:22 PDT 2025
================
@@ -1823,9 +1826,127 @@ extern "C" void *__libunwind_shstk_get_jump_target() {
#endif
class _LIBUNWIND_HIDDEN Registers_arm64 {
+ struct GPRs;
+
+private:
+ /// The program counter is used effectively as a return address
+ /// when the context is restored therefore protect it with PAC.
+ /// The base address of the context is used with the A key for
+ /// authentication and signing. Return address authentication is
+ /// still managed according to the unwind info. In some cases
+ /// the LR contains significant bits in the space for the PAC bits the
+ /// value of the PC is stored in 2 halfs and each signed.
+ inline uint64_t getDiscriminator() const {
+ return reinterpret_cast<uint64_t>(this);
+ }
+#if defined(_LIBUNWIND_AARCH64_PC_PROTECTION)
+#if defined(_LIBUNWIND_PTRAUTH_AVAILABLE)
+/// Use Pointer Authentication Intrinsics when available.
+#define __libunwind_ptrauth_auth_data(__value, __key, __discriminator) \
+ ptrauth_auth_data(__value, __key, __discriminator)
+#define __libunwind_ptrauth_auth_and_resign(pointer, oldKey, oldDiscriminator, \
+ newKey, newDiscriminator) \
+ ptrauth_auth_and_resign(pointer, oldKey, oldDiscriminator, newKey, \
+ newDiscriminator)
+#define __libunwind_ptrauth_sign_unauthenticated(__value, __key, __data) \
+ ptrauth_sign_unauthenticated(__value, __key, __data)
+#else // !_LIBUNWIND_PTRAUTH_AVAILABLE
+ typedef enum {
+ ptrauth_key_asia = 0,
+ } ptrauth_key;
+ /// Using only the NOP space compatible instructions. FPAC might not be
+ /// available on the target so a manual check is added.
+ inline void *__libunwind_ptrauth_strip(void *__value,
+ ptrauth_key __key) const {
+ assert(__key == ptrauth_key_asia && "Only A key is supported");
+ void *__return = 0;
+ asm("mov x30, %[__value] \r\n"
+ "hint 0x7 \r\n" // xpaclri
+ "mov %[__return], x30 \r\n"
+ : [__return] "+r"(__return)
+ : [__value] "r"(__value)
+ : "x30");
+ return __return;
+ }
+
+ inline void *__libunwind_ptrauth_auth_data(void *__value, ptrauth_key __key,
+ uint64_t __discriminator) const {
+ assert(__key == ptrauth_key_asia && "Only A key is supported");
+ register void *x17 __asm("x17") = __value;
+ register uintptr_t x16 __asm("x16") = __discriminator;
+ asm("hint 0xc" // autia1716
+ : "+r"(x17)
+ : "r"(x16)
+ :);
+ if (x17 != __libunwind_ptrauth_strip(__value, __key))
+ _LIBUNWIND_ABORT("ptrauth authentication failure");
+ return x17;
+ }
+
+ inline void *
+ __libunwind_ptrauth_sign_unauthenticated(void *__value, ptrauth_key __key,
+ uint64_t __discriminator) const {
+ assert(__key == ptrauth_key_asia && "Only A key is supported");
+ register void *x17 __asm("x17") = __value;
+ register uint64_t x16 __asm("x16") = __discriminator;
+ asm("hint 0x8" : "+r"(x17) : "r"(x16));
+ return x17;
+ }
+
+ inline void *__libunwind_ptrauth_auth_and_resign(
+ void *pointer, ptrauth_key oldKey, uint64_t oldDiscriminator,
+ ptrauth_key newKey, uint64_t newDiscriminator) const {
+ return __libunwind_ptrauth_sign_unauthenticated(
+ __libunwind_ptrauth_auth_data(pointer, oldKey, oldDiscriminator),
+ newKey, newDiscriminator);
+ }
+#endif
+ // Authenticate the currently stored PC and return it's raw value.
+ inline uint64_t authPC(const struct GPRs *gprs,
+ uint64_t discriminator) const {
+ uint64_t lower = (uint64_t)__libunwind_ptrauth_auth_data(
+ (void *)gprs->__pc, ptrauth_key_asia, discriminator);
+ uint64_t upper = (uint64_t)__libunwind_ptrauth_auth_data(
+ (void *)gprs->__pc2, ptrauth_key_asia, discriminator);
+ return (upper << 32) | lower;
+ }
+
+ // Sign and store the new PC.
+ inline void updatePC(uint64_t value) {
----------------
asl wrote:
This is a direct signing oracle.
https://github.com/llvm/llvm-project/pull/113368
More information about the cfe-commits
mailing list