e940beb3af
Resolves: #2305877
334 lines
11 KiB
Diff
334 lines
11 KiB
Diff
From 45d284f2d066cc3a080c5be88e51b4d934349797 Mon Sep 17 00:00:00 2001
|
|
From: Bill Roberts <152999275+billatarm@users.noreply.github.com>
|
|
Date: Sat, 1 Jun 2024 12:34:53 -0500
|
|
Subject: [PATCH 3/7] aarch64: support pointer authentication (#834)
|
|
Content-type: text/plain; charset=UTF-8
|
|
|
|
* aarch64: fix callstack in ffi_call_SYSV
|
|
|
|
The debug stack gets corrupted between the frame and stack pivots, update
|
|
the CFI directives so the call stack stays correct in the debugger.
|
|
|
|
str x9, [x1, #32] // stack is ffi_call_SYSV() -> ffi_call_int() -> ffi_call_int() -> main() (good)
|
|
mov x29, x1 // stack is ffi_call_SYSV() -> ffi_call_int() -> ffi_call_int() -> ffi_call() -> main() (bad)
|
|
mov sp, x0 // stack is ffi_call_SYSV() -> ffi_call_int() -> ffi_call_int() -> main() (good)
|
|
|
|
The CFA data needs to be updated around the pivots, after this patch the
|
|
callstack stays correct.
|
|
|
|
Signed-off-by: Bill Roberts <bill.roberts@arm.com>
|
|
|
|
* aarch64: remove uneeded CFI directive
|
|
|
|
This directive doesn't actually set the CFA to anything valid, and
|
|
during unwinding this isn't even used. Note that the PAC/Darwin usage
|
|
is quite suspect as well, as the CFA is either x1 or x29 after the frame
|
|
pivot, and the CFA address is what's used as the modifier when verifying
|
|
the PAC. At least this is the behavior on Linux with PAC, I need to
|
|
verify ARME ABI unwinding. So for now leave Darwin as is.
|
|
|
|
Signed-off-by: Bill Roberts <bill.roberts@arm.com>
|
|
|
|
* ptrauth: rename define for clarity
|
|
|
|
Rename the HAVE_PTRAUTH define for clarity that its associated with the
|
|
ARM64E ABI and not the ARM64 ABI that can be supported on Linux and
|
|
enabled with -mbranch-protection=standard.
|
|
|
|
Signed-off-by: Bill Roberts <bill.roberts@arm.com>
|
|
|
|
* aarch64: add PAC support to ffi_call_SYSV
|
|
|
|
Support AARCH64 Pointer Authentication Codes (PAC) within ffi_call_SYSV
|
|
and support exception unwinding.
|
|
|
|
The Linux ABI for PAC is to use paciasp/autiasp instructions which also
|
|
have hint space equivelent instructions. They sign the LR (x30) with the
|
|
A key and the current stack pointer as the salt. Note that this can also be
|
|
configured to use the B key and will use pacibsp/autibsp hint instructions.
|
|
|
|
The Linux ABI for exception frame data when PAC is enabled assumes that the
|
|
Connonical Frame Address, or CFA is equal to the stack pointer. I.E sp is
|
|
equal to x29 (fp). When the unwinder is invoked the cfa will point to
|
|
the frame which will include the *signed* return address from the LR.
|
|
This will then be passed to __builtin_aarch64_autia1716 where the CFA
|
|
will be used as the salt and stored to register x16 and register x17
|
|
will contain the signed address to demangle. This can be noted in:
|
|
- https://github.com/gcc-mirror/gcc/blob/d6d7afcdbc04adb0ec42a44b2d7e05600945af42/libgcc/config/aarch64/aarch64-unwind.h#L56
|
|
|
|
The other required portion of this is to indicate to the unwinder that
|
|
this is a signed address that needs to go the special demangle route in
|
|
the unwinder. This is accomplished by using CFI directive "cfi_window_save"
|
|
which marks that frame as being signed.
|
|
|
|
Putting all of this together is a bit tricky, as the internals of
|
|
ffi_call_SYSV the callee allocates its stack and frame and passes it in
|
|
arg1 (x0) and arg2 (x1) to the called function, where that function
|
|
pivots its stack, so care must be taken to get the sp == fp before
|
|
paciasp is called and also restore that state before autiasp is called.
|
|
|
|
Signed-off-by: Bill Roberts <bill.roberts@arm.com>
|
|
|
|
---------
|
|
|
|
Signed-off-by: Bill Roberts <bill.roberts@arm.com>
|
|
---
|
|
configure.ac | 6 ++--
|
|
include/ffi_cfi.h | 2 ++
|
|
src/aarch64/ffi.c | 4 +--
|
|
src/aarch64/internal.h | 76 ++++++++++++++++++++++++++++++++----------
|
|
src/aarch64/sysv.S | 20 ++++++-----
|
|
src/closures.c | 6 ++--
|
|
6 files changed, 81 insertions(+), 33 deletions(-)
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 816bfd6..b35a999 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -189,17 +189,17 @@ AC_CACHE_CHECK([whether compiler supports pointer authentication],
|
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
|
|
#ifdef __clang__
|
|
# if __has_feature(ptrauth_calls)
|
|
-# define HAVE_PTRAUTH 1
|
|
+# define HAVE_ARM64E_PTRAUTH 1
|
|
# endif
|
|
#endif
|
|
|
|
-#ifndef HAVE_PTRAUTH
|
|
+#ifndef HAVE_ARM64E_PTRAUTH
|
|
# error Pointer authentication not supported
|
|
#endif
|
|
]])],[libffi_cv_as_ptrauth=yes],[libffi_cv_as_ptrauth=no])
|
|
])
|
|
if test "x$libffi_cv_as_ptrauth" = xyes; then
|
|
- AC_DEFINE(HAVE_PTRAUTH, 1,
|
|
+ AC_DEFINE(HAVE_ARM64E_PTRAUTH, 1,
|
|
[Define if your compiler supports pointer authentication.])
|
|
fi
|
|
|
|
diff --git a/include/ffi_cfi.h b/include/ffi_cfi.h
|
|
index f4c292d..8565663 100644
|
|
--- a/include/ffi_cfi.h
|
|
+++ b/include/ffi_cfi.h
|
|
@@ -49,6 +49,7 @@
|
|
# define cfi_personality(enc, exp) .cfi_personality enc, exp
|
|
# define cfi_lsda(enc, exp) .cfi_lsda enc, exp
|
|
# define cfi_escape(...) .cfi_escape __VA_ARGS__
|
|
+# define cfi_window_save .cfi_window_save
|
|
|
|
#else
|
|
|
|
@@ -71,6 +72,7 @@
|
|
# define cfi_personality(enc, exp)
|
|
# define cfi_lsda(enc, exp)
|
|
# define cfi_escape(...)
|
|
+# define cfi_window_save
|
|
|
|
#endif /* HAVE_AS_CFI_PSEUDO_OP */
|
|
#endif /* FFI_CFI_H */
|
|
diff --git a/src/aarch64/ffi.c b/src/aarch64/ffi.c
|
|
index b13738e..964934d 100644
|
|
--- a/src/aarch64/ffi.c
|
|
+++ b/src/aarch64/ffi.c
|
|
@@ -63,7 +63,7 @@ struct call_context
|
|
#if FFI_EXEC_TRAMPOLINE_TABLE
|
|
|
|
#ifdef __MACH__
|
|
-#ifdef HAVE_PTRAUTH
|
|
+#ifdef HAVE_ARM64E_PTRAUTH
|
|
#include <ptrauth.h>
|
|
#endif
|
|
#include <mach/vm_param.h>
|
|
@@ -877,7 +877,7 @@ ffi_prep_closure_loc (ffi_closure *closure,
|
|
|
|
#if FFI_EXEC_TRAMPOLINE_TABLE
|
|
# ifdef __MACH__
|
|
-# ifdef HAVE_PTRAUTH
|
|
+# ifdef HAVE_ARM64E_PTRAUTH
|
|
codeloc = ptrauth_auth_data(codeloc, ptrauth_key_function_pointer, 0);
|
|
# endif
|
|
void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE);
|
|
diff --git a/src/aarch64/internal.h b/src/aarch64/internal.h
|
|
index b5d102b..c39f9cb 100644
|
|
--- a/src/aarch64/internal.h
|
|
+++ b/src/aarch64/internal.h
|
|
@@ -81,20 +81,62 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
/* Helpers for writing assembly compatible with arm ptr auth */
|
|
#ifdef LIBFFI_ASM
|
|
|
|
-#ifdef HAVE_PTRAUTH
|
|
-#define SIGN_LR pacibsp
|
|
-#define SIGN_LR_WITH_REG(x) pacib lr, x
|
|
-#define AUTH_LR_AND_RET retab
|
|
-#define AUTH_LR_WITH_REG(x) autib lr, x
|
|
-#define BRANCH_AND_LINK_TO_REG blraaz
|
|
-#define BRANCH_TO_REG braaz
|
|
-#else
|
|
-#define SIGN_LR
|
|
-#define SIGN_LR_WITH_REG(x)
|
|
-#define AUTH_LR_AND_RET ret
|
|
-#define AUTH_LR_WITH_REG(x)
|
|
-#define BRANCH_AND_LINK_TO_REG blr
|
|
-#define BRANCH_TO_REG br
|
|
-#endif
|
|
-
|
|
-#endif
|
|
+ #if defined(HAVE_ARM64E_PTRAUTH)
|
|
+ /* ARM64E ABI For Darwin */
|
|
+ #define SIGN_LR pacibsp
|
|
+ #define SIGN_LR_WITH_REG(x) pacib lr, x
|
|
+ #define AUTH_LR_AND_RET retab
|
|
+ #define AUTH_LR_WITH_REG(x) autib lr, x
|
|
+ #define BRANCH_AND_LINK_TO_REG blraaz
|
|
+ #define BRANCH_TO_REG braaz
|
|
+ #define PAC_CFI_WINDOW_SAVE
|
|
+ /* Linux PAC Support */
|
|
+ #elif defined(__ARM_FEATURE_PAC_DEFAULT)
|
|
+ #define GNU_PROPERTY_AARCH64_POINTER_AUTH (1 << 1)
|
|
+ #define PAC_CFI_WINDOW_SAVE cfi_window_save
|
|
+ #define TMP_REG x9
|
|
+ #define BRANCH_TO_REG br
|
|
+ #define BRANCH_AND_LINK_TO_REG blr
|
|
+ #define SIGN_LR_LINUX_ONLY SIGN_LR
|
|
+ /* Which key to sign with? */
|
|
+ #if (__ARM_FEATURE_PAC_DEFAULT & 1) == 1
|
|
+ /* Signed with A-key */
|
|
+ #define SIGN_LR hint #25 /* paciasp */
|
|
+ #define AUTH_LR hint #29 /* autiasp */
|
|
+ #else
|
|
+ /* Signed with B-key */
|
|
+ #define SIGN_LR hint #27 /* pacibsp */
|
|
+ #define AUTH_LR hint #31 /* autibsp */
|
|
+ #endif /* __ARM_FEATURE_PAC_DEFAULT */
|
|
+ #define AUTH_LR_WITH_REG(x) _auth_lr_with_reg x
|
|
+.macro _auth_lr_with_reg modifier
|
|
+ mov TMP_REG, sp
|
|
+ mov sp, \modifier
|
|
+ AUTH_LR
|
|
+ mov sp, TMP_REG
|
|
+.endm
|
|
+ #define SIGN_LR_WITH_REG(x) _sign_lr_with_reg x
|
|
+.macro _sign_lr_with_reg modifier
|
|
+ mov TMP_REG, sp
|
|
+ mov sp, \modifier
|
|
+ SIGN_LR
|
|
+ mov sp, TMP_REG
|
|
+.endm
|
|
+ #define AUTH_LR_AND_RET _auth_lr_and_ret modifier
|
|
+.macro _auth_lr_and_ret modifier
|
|
+ AUTH_LR
|
|
+ ret
|
|
+.endm
|
|
+ #undef TMP_REG
|
|
+
|
|
+ /* No Pointer Auth */
|
|
+ #else
|
|
+ #define SIGN_LR
|
|
+ #define SIGN_LR_WITH_REG(x)
|
|
+ #define AUTH_LR_AND_RET ret
|
|
+ #define AUTH_LR_WITH_REG(x)
|
|
+ #define BRANCH_AND_LINK_TO_REG blr
|
|
+ #define BRANCH_TO_REG br
|
|
+ #define PAC_CFI_WINDOW_SAVE
|
|
+ #endif /* HAVE_ARM64E_PTRAUTH */
|
|
+#endif /* LIBFFI_ASM */
|
|
diff --git a/src/aarch64/sysv.S b/src/aarch64/sysv.S
|
|
index 60cfa50..6a9a561 100644
|
|
--- a/src/aarch64/sysv.S
|
|
+++ b/src/aarch64/sysv.S
|
|
@@ -92,27 +92,27 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
cfi_startproc
|
|
CNAME(ffi_call_SYSV):
|
|
BTI_C
|
|
- /* Sign the lr with x1 since that is where it will be stored */
|
|
+ PAC_CFI_WINDOW_SAVE
|
|
+ /* Sign the lr with x1 since that is the CFA which is the modifer used in auth instructions */
|
|
SIGN_LR_WITH_REG(x1)
|
|
|
|
- /* Use a stack frame allocated by our caller. */
|
|
-#if defined(HAVE_PTRAUTH) && defined(__APPLE__)
|
|
+#if defined(HAVE_ARM64E_PTRAUTH) && defined(__APPLE__)
|
|
/* darwin's libunwind assumes that the cfa is the sp and that's the data
|
|
* used to sign the lr. In order to allow unwinding through this
|
|
* function it is necessary to point the cfa at the signing register.
|
|
*/
|
|
cfi_def_cfa(x1, 0);
|
|
-#else
|
|
- cfi_def_cfa(x1, 40);
|
|
#endif
|
|
+ /* Use a stack frame allocated by our caller. */
|
|
stp x29, x30, [x1]
|
|
+ cfi_def_cfa_register(x1)
|
|
+ cfi_rel_offset (x29, 0)
|
|
+ cfi_rel_offset (x30, 8)
|
|
mov x9, sp
|
|
str x9, [x1, #32]
|
|
mov x29, x1
|
|
- mov sp, x0
|
|
cfi_def_cfa_register(x29)
|
|
- cfi_rel_offset (x29, 0)
|
|
- cfi_rel_offset (x30, 8)
|
|
+ mov sp, x0
|
|
|
|
mov x9, x2 /* save fn */
|
|
mov x8, x3 /* install structure return */
|
|
@@ -326,6 +326,7 @@ CNAME(ffi_closure_SYSV_V):
|
|
cfi_startproc
|
|
BTI_C
|
|
SIGN_LR
|
|
+ PAC_CFI_WINDOW_SAVE
|
|
stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
|
|
cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
|
|
cfi_rel_offset (x29, 0)
|
|
@@ -351,6 +352,7 @@ CNAME(ffi_closure_SYSV_V):
|
|
CNAME(ffi_closure_SYSV):
|
|
BTI_C
|
|
SIGN_LR
|
|
+ PAC_CFI_WINDOW_SAVE
|
|
stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
|
|
cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
|
|
cfi_rel_offset (x29, 0)
|
|
@@ -648,6 +650,8 @@ CNAME(ffi_go_closure_SYSV_V):
|
|
cfi_startproc
|
|
CNAME(ffi_go_closure_SYSV):
|
|
BTI_C
|
|
+ SIGN_LR_LINUX_ONLY
|
|
+ PAC_CFI_WINDOW_SAVE
|
|
stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
|
|
cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
|
|
cfi_rel_offset (x29, 0)
|
|
diff --git a/src/closures.c b/src/closures.c
|
|
index 67a94a8..02cf78f 100644
|
|
--- a/src/closures.c
|
|
+++ b/src/closures.c
|
|
@@ -164,7 +164,7 @@ ffi_tramp_is_present (__attribute__((unused)) void *ptr)
|
|
|
|
#include <mach/mach.h>
|
|
#include <pthread.h>
|
|
-#ifdef HAVE_PTRAUTH
|
|
+#ifdef HAVE_ARM64E_PTRAUTH
|
|
#include <ptrauth.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
@@ -223,7 +223,7 @@ ffi_trampoline_table_alloc (void)
|
|
/* Remap the trampoline table on top of the placeholder page */
|
|
trampoline_page = config_page + PAGE_MAX_SIZE;
|
|
|
|
-#ifdef HAVE_PTRAUTH
|
|
+#ifdef HAVE_ARM64E_PTRAUTH
|
|
trampoline_page_template = (vm_address_t)(uintptr_t)ptrauth_auth_data((void *)&ffi_closure_trampoline_table_page, ptrauth_key_function_pointer, 0);
|
|
#else
|
|
trampoline_page_template = (vm_address_t)&ffi_closure_trampoline_table_page;
|
|
@@ -268,7 +268,7 @@ ffi_trampoline_table_alloc (void)
|
|
ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
|
|
entry->trampoline =
|
|
(void *) (trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
|
|
-#ifdef HAVE_PTRAUTH
|
|
+#ifdef HAVE_ARM64E_PTRAUTH
|
|
entry->trampoline = ptrauth_sign_unauthenticated(entry->trampoline, ptrauth_key_function_pointer, 0);
|
|
#endif
|
|
|
|
--
|
|
2.46.0
|
|
|