Message ID | 20190529190332.29753-7-kristina.martsenko@arm.com (mailing list archive) |
---|---|
State | RFC |
Headers | show |
Series | arm64: return address signing | expand |
On Wed, May 29, 2019 at 08:03:31PM +0100, Kristina Martsenko wrote: > From: Mark Rutland <mark.rutland@arm.com> > > When we enable pointer authentication in the kernel, LR values saved to > the stack will have a PAC which we must strip in order to retrieve the > real return address. > > Strip PACs when unwinding the stack in order to account for this. > > Reviewed-by: Amit Daniel Kachhap <amit.kachhap@arm.com> > Signed-off-by: Mark Rutland <mark.rutland@arm.com> > Signed-off-by: Kristina Martsenko <kristina.martsenko@arm.com> Reviewed-by: Kees Cook <keescook@chromium.org> -Kees > --- > > Changes since RFC v1: > - Moved the patch later in the series > > arch/arm64/include/asm/pointer_auth.h | 10 +++++++--- > arch/arm64/kernel/stacktrace.c | 3 +++ > 2 files changed, 10 insertions(+), 3 deletions(-) > > diff --git a/arch/arm64/include/asm/pointer_auth.h b/arch/arm64/include/asm/pointer_auth.h > index 79f35f5ecff5..5491c34b4dc3 100644 > --- a/arch/arm64/include/asm/pointer_auth.h > +++ b/arch/arm64/include/asm/pointer_auth.h > @@ -80,12 +80,16 @@ extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg); > * The EL0 pointer bits used by a pointer authentication code. > * This is dependent on TBI0 being enabled, or bits 63:56 would also apply. > */ > -#define ptrauth_user_pac_mask() GENMASK(54, vabits_user) > +#define ptrauth_user_pac_mask() GENMASK(54, vabits_user) > + > +#define ptrauth_kernel_pac_mask() (GENMASK(63, 56) | GENMASK(54, VA_BITS)) > > -/* Only valid for EL0 TTBR0 instruction pointers */ > static inline unsigned long ptrauth_strip_insn_pac(unsigned long ptr) > { > - return ptr & ~ptrauth_user_pac_mask(); > + if (ptr & BIT_ULL(55)) > + return ptr | ptrauth_kernel_pac_mask(); > + else > + return ptr & ~ptrauth_user_pac_mask(); > } > > #define ptrauth_thread_init_user(tsk) \ > diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c > index d908b5e9e949..df07c27a9673 100644 > --- a/arch/arm64/kernel/stacktrace.c > +++ b/arch/arm64/kernel/stacktrace.c > @@ -24,6 +24,7 @@ > #include <linux/stacktrace.h> > > #include <asm/irq.h> > +#include <asm/pointer_auth.h> > #include <asm/stack_pointer.h> > #include <asm/stacktrace.h> > > @@ -56,6 +57,8 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame) > frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp)); > frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8)); > > + frame->pc = ptrauth_strip_insn_pac(frame->pc); > + > #ifdef CONFIG_FUNCTION_GRAPH_TRACER > if (tsk->ret_stack && > (frame->pc == (unsigned long)return_to_handler)) { > -- > 2.11.0 >
diff --git a/arch/arm64/include/asm/pointer_auth.h b/arch/arm64/include/asm/pointer_auth.h index 79f35f5ecff5..5491c34b4dc3 100644 --- a/arch/arm64/include/asm/pointer_auth.h +++ b/arch/arm64/include/asm/pointer_auth.h @@ -80,12 +80,16 @@ extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg); * The EL0 pointer bits used by a pointer authentication code. * This is dependent on TBI0 being enabled, or bits 63:56 would also apply. */ -#define ptrauth_user_pac_mask() GENMASK(54, vabits_user) +#define ptrauth_user_pac_mask() GENMASK(54, vabits_user) + +#define ptrauth_kernel_pac_mask() (GENMASK(63, 56) | GENMASK(54, VA_BITS)) -/* Only valid for EL0 TTBR0 instruction pointers */ static inline unsigned long ptrauth_strip_insn_pac(unsigned long ptr) { - return ptr & ~ptrauth_user_pac_mask(); + if (ptr & BIT_ULL(55)) + return ptr | ptrauth_kernel_pac_mask(); + else + return ptr & ~ptrauth_user_pac_mask(); } #define ptrauth_thread_init_user(tsk) \ diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index d908b5e9e949..df07c27a9673 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -24,6 +24,7 @@ #include <linux/stacktrace.h> #include <asm/irq.h> +#include <asm/pointer_auth.h> #include <asm/stack_pointer.h> #include <asm/stacktrace.h> @@ -56,6 +57,8 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame) frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp)); frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8)); + frame->pc = ptrauth_strip_insn_pac(frame->pc); + #ifdef CONFIG_FUNCTION_GRAPH_TRACER if (tsk->ret_stack && (frame->pc == (unsigned long)return_to_handler)) {