Skip to content

Commit ca70859

Browse files
mrutland-armwilldeacon
authored andcommitted
arm64: use XPACLRI to strip PAC
Currently we strip the PAC from pointers using C code, which requires generating bitmasks, and conditionally clearing/setting bits depending on bit 55. We can do better by using XPACLRI directly. When the logic was originally written to strip PACs from user pointers, contemporary toolchains used for the kernel had assemblers which were unaware of the PAC instructions. As stripping the PAC from userspace pointers required unconditional clearing of a fixed set of bits (which could be performed with a single instruction), it was simpler to implement the masking in C than it was to make use of XPACI or XPACLRI. When support for in-kernel pointer authentication was added, the stripping logic was extended to cover TTBR1 pointers, requiring several instructions to handle whether to clear/set bits dependent on bit 55 of the pointer. This patch simplifies the stripping of PACs by using XPACLRI directly, as contemporary toolchains do within __builtin_return_address(). This saves a number of instructions, especially where __builtin_return_address() does not implicitly strip the PAC but is heavily used (e.g. with tracepoints). As the kernel might be compiled with an assembler without knowledge of XPACLRI, it is assembled using the 'HINT #7' alias, which results in an identical opcode. At the same time, I've split ptrauth_strip_insn_pac() into ptrauth_strip_user_insn_pac() and ptrauth_strip_kernel_insn_pac() helpers so that we can avoid unnecessary PAC stripping when pointer authentication is not in use in userspace or kernel respectively. The underlying xpaclri() macro uses inline assembly which clobbers x30. The clobber causes the compiler to save/restore the original x30 value in a frame record (protected with PACIASP and AUTIASP when in-kernel authentication is enabled), so this does not provide a gadget to alter the return address. Similarly this does not adversely affect unwinding due to the presence of the frame record. The ptrauth_user_pac_mask() and ptrauth_kernel_pac_mask() are exported from the kernel in ptrace and core dumps, so these are retained. A subsequent patch will move them out of <asm/compiler.h>. Signed-off-by: Mark Rutland <[email protected]> Cc: Amit Daniel Kachhap <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: James Morse <[email protected]> Cc: Kristina Martsenko <[email protected]> Cc: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 9df3f50 commit ca70859

File tree

5 files changed

+28
-16
lines changed

5 files changed

+28
-16
lines changed

arch/arm64/include/asm/compiler.h

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,33 @@
1515
#define ptrauth_user_pac_mask() GENMASK_ULL(54, vabits_actual)
1616
#define ptrauth_kernel_pac_mask() GENMASK_ULL(63, vabits_actual)
1717

18-
/* Valid for EL0 TTBR0 and EL1 TTBR1 instruction pointers */
19-
#define ptrauth_clear_pac(ptr) \
20-
((ptr & BIT_ULL(55)) ? (ptr | ptrauth_kernel_pac_mask()) : \
21-
(ptr & ~ptrauth_user_pac_mask()))
18+
#define xpaclri(ptr) \
19+
({ \
20+
register unsigned long __xpaclri_ptr asm("x30") = (ptr); \
21+
\
22+
asm( \
23+
ARM64_ASM_PREAMBLE \
24+
" hint #7\n" \
25+
: "+r" (__xpaclri_ptr)); \
26+
\
27+
__xpaclri_ptr; \
28+
})
2229

23-
#if defined(CONFIG_ARM64_PTR_AUTH_KERNEL) && \
24-
!defined(CONFIG_BUILTIN_RETURN_ADDRESS_STRIPS_PAC)
30+
#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
31+
#define ptrauth_strip_kernel_insn_pac(ptr) xpaclri(ptr)
32+
#else
33+
#define ptrauth_strip_kernel_insn_pac(ptr) (ptr)
34+
#endif
35+
36+
#ifdef CONFIG_ARM64_PTR_AUTH
37+
#define ptrauth_strip_user_insn_pac(ptr) xpaclri(ptr)
38+
#else
39+
#define ptrauth_strip_user_insn_pac(ptr) (ptr)
40+
#endif
41+
42+
#if !defined(CONFIG_BUILTIN_RETURN_ADDRESS_STRIPS_PAC)
2543
#define __builtin_return_address(val) \
26-
(void *)(ptrauth_clear_pac((unsigned long)__builtin_return_address(val)))
44+
(void *)(ptrauth_strip_kernel_insn_pac((unsigned long)__builtin_return_address(val)))
2745
#endif
2846

2947
#endif /* __ASM_COMPILER_H */

arch/arm64/include/asm/pointer_auth.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,6 @@ extern int ptrauth_set_enabled_keys(struct task_struct *tsk, unsigned long keys,
9797
unsigned long enabled);
9898
extern int ptrauth_get_enabled_keys(struct task_struct *tsk);
9999

100-
static inline unsigned long ptrauth_strip_insn_pac(unsigned long ptr)
101-
{
102-
return ptrauth_clear_pac(ptr);
103-
}
104-
105100
static __always_inline void ptrauth_enable(void)
106101
{
107102
if (!system_supports_address_auth())
@@ -133,7 +128,6 @@ static __always_inline void ptrauth_enable(void)
133128
#define ptrauth_prctl_reset_keys(tsk, arg) (-EINVAL)
134129
#define ptrauth_set_enabled_keys(tsk, keys, enabled) (-EINVAL)
135130
#define ptrauth_get_enabled_keys(tsk) (-EINVAL)
136-
#define ptrauth_strip_insn_pac(lr) (lr)
137131
#define ptrauth_suspend_exit()
138132
#define ptrauth_thread_init_user()
139133
#define ptrauth_thread_switch_user(tsk)

arch/arm64/kernel/perf_callchain.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ user_backtrace(struct frame_tail __user *tail,
3838
if (err)
3939
return NULL;
4040

41-
lr = ptrauth_strip_insn_pac(buftail.lr);
41+
lr = ptrauth_strip_user_insn_pac(buftail.lr);
4242

4343
perf_callchain_store(entry, lr);
4444

arch/arm64/kernel/process.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ void __show_regs(struct pt_regs *regs)
217217

218218
if (!user_mode(regs)) {
219219
printk("pc : %pS\n", (void *)regs->pc);
220-
printk("lr : %pS\n", (void *)ptrauth_strip_insn_pac(lr));
220+
printk("lr : %pS\n", (void *)ptrauth_strip_kernel_insn_pac(lr));
221221
} else {
222222
printk("pc : %016llx\n", regs->pc);
223223
printk("lr : %016llx\n", lr);

arch/arm64/kernel/stacktrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ unwind_next(struct unwind_state *state)
120120
if (err)
121121
return err;
122122

123-
state->pc = ptrauth_strip_insn_pac(state->pc);
123+
state->pc = ptrauth_strip_kernel_insn_pac(state->pc);
124124

125125
return unwind_recover_return_address(state);
126126
}

0 commit comments

Comments
 (0)