================
@@ -683,42 +684,139 @@ 
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
   ldp    x28,x29, [x0, #0x0E0]
 
 #if defined(__ARM_FP) && __ARM_FP != 0
-  ldp    d0, d1,  [x0, #0x110]
-  ldp    d2, d3,  [x0, #0x120]
-  ldp    d4, d5,  [x0, #0x130]
-  ldp    d6, d7,  [x0, #0x140]
-  ldp    d8, d9,  [x0, #0x150]
-  ldp    d10,d11, [x0, #0x160]
-  ldp    d12,d13, [x0, #0x170]
-  ldp    d14,d15, [x0, #0x180]
-  ldp    d16,d17, [x0, #0x190]
-  ldp    d18,d19, [x0, #0x1A0]
-  ldp    d20,d21, [x0, #0x1B0]
-  ldp    d22,d23, [x0, #0x1C0]
-  ldp    d24,d25, [x0, #0x1D0]
-  ldp    d26,d27, [x0, #0x1E0]
-  ldp    d28,d29, [x0, #0x1F0]
-  ldr    d30,     [x0, #0x200]
-  ldr    d31,     [x0, #0x208]
+  ldp    d0, d1,  [x0, #0x120]
+  ldp    d2, d3,  [x0, #0x130]
+  ldp    d4, d5,  [x0, #0x140]
+  ldp    d6, d7,  [x0, #0x150]
+  ldp    d8, d9,  [x0, #0x160]
+  ldp    d10,d11, [x0, #0x170]
+  ldp    d12,d13, [x0, #0x180]
+  ldp    d14,d15, [x0, #0x190]
+  ldp    d16,d17, [x0, #0x1A0]
+  ldp    d18,d19, [x0, #0x1B0]
+  ldp    d20,d21, [x0, #0x1C0]
+  ldp    d22,d23, [x0, #0x1D0]
+  ldp    d24,d25, [x0, #0x1E0]
+  ldp    d26,d27, [x0, #0x1F0]
+  ldr    d28,     [x0, #0x200]
+  ldr    d29,     [x0, #0x208]
+  ldr    d30,     [x0, #0x210]
+  ldr    d31,     [x0, #0x218]
 #endif
+
+  // The lr value stored in __pc might be signed with IA/IB key (as described
+  // by __ra_sign.__use_b_key field) and &__pc address as a modifier.
+  // If the lr value is signed, re-sign that with the corresponding key
+  // and initial signing scheme using __sp as a modifier and potentially
+  // involving a second modifier (as described by (__ra_sign.__state & 2)).
+
+  ldr    x14,     [x0, #0x0F8]  // x14 = __sp
----------------
kovdan01 wrote:

This mimics existing behavior of Apple's arm64e and Linux's pauthtest. 
Particularly, if the pointer is signed, we re-sign that so it is signed with 
the original signing scheme (rather then with `&__pc` address as a modifier). 
After that, we authenticate re-signed pointer at return.

This is bulky and we can probably do it more elegant. Would be glad to see 
thoughts of anyone interested regarding this. See my thoughts below.

When implementing this, I was focused on maintaining the following three 
properties of current implementation.

1. We should not do any loads from stack after `sp` is restored (see 
d5323f6a707e376aab20ebe7864a78fc38fcedaa).
2. The only scratch registers which are allowed to be clobbered are x16 and 
x17, all other registers are restored from the context structure.
3. Since we are using hint-encoded instructions to maintain compatibility with 
old hardware, authenticated return is done with regular `ret` following `auti*` 
instruction. I assumed that we must keep these two instructions together 
without inserting anything else between them to reduce the time when `lr` 
remains unsigned.

If we could weaken property 2 (e.g. allow x14 and x15 to be clobbered) or 
property 3 (e.g. allow code between `auti*` and `ret`), we might make the whole 
implementation much simpler. Particularly, instead of doing a re-sign with 
almost immediate auth, we might just do one auth. The three limitations listed 
below do not allow us to have a nice implementation because we need to deal 
with three conditions for choosing between 5 possible configurations of RA sign 
state (not signed, signed with IA and no PC modifier, signed with IB and no PC 
modifier, signed with IA and PC modifier, signed with IB and PC modifier).

https://github.com/llvm/llvm-project/pull/171717
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to