Ivan T. Ivanov e55d0f
From: James Morse <james.morse@arm.com>
Ivan T. Ivanov e55d0f
Date: Mon, 22 Jul 2019 16:11:48 +0100
Ivan T. Ivanov e55d0f
Subject: arm64: entry: SP Alignment Fault doesn't write to FAR_EL1
Ivan T. Ivanov e55d0f
Git-commit: 40ca0ce56d4bb889dc43b455c55398468115569a
Ivan T. Ivanov e55d0f
Patch-mainline: v5.3-rc2
Ivan T. Ivanov e55d0f
References: git-fixes
Ivan T. Ivanov e55d0f
Ivan T. Ivanov e55d0f
Comparing the arm-arm's  pseudocode for AArch64.PCAlignmentFault() with
Ivan T. Ivanov e55d0f
AArch64.SPAlignmentFault() shows that SP faults don't copy the faulty-SP
Ivan T. Ivanov e55d0f
to FAR_EL1, but this is where we read from, and the address we provide
Ivan T. Ivanov e55d0f
to user-space with the BUS_ADRALN signal.
Ivan T. Ivanov e55d0f
Ivan T. Ivanov e55d0f
For user-space this value will be UNKNOWN due to the previous ERET to
Ivan T. Ivanov e55d0f
user-space. If the last value is preserved, on systems with KASLR or KPTI
Ivan T. Ivanov e55d0f
this will be the user-space link-register left in FAR_EL1 by tramp_exit().
Ivan T. Ivanov e55d0f
Fix this to retrieve the original sp_el0 value, and pass this to
Ivan T. Ivanov e55d0f
do_sp_pc_fault().
Ivan T. Ivanov e55d0f
Ivan T. Ivanov e55d0f
SP alignment faults from EL1 will cause us to take the fault again when
Ivan T. Ivanov e55d0f
trying to store the pt_regs. This eventually takes us to the overflow
Ivan T. Ivanov e55d0f
stack. Remove the ESR_ELx_EC_SP_ALIGN check as we will never make it
Ivan T. Ivanov e55d0f
this far.
Ivan T. Ivanov e55d0f
Ivan T. Ivanov e55d0f
Fixes: 60ffc30d5652 ("arm64: Exception handling")
Ivan T. Ivanov e55d0f
Signed-off-by: James Morse <james.morse@arm.com>
Ivan T. Ivanov e55d0f
[will: change label name and fleshed out comment]
Ivan T. Ivanov e55d0f
Signed-off-by: Will Deacon <will@kernel.org>
Ivan T. Ivanov e55d0f
Acked-by: Ivan T. Ivanov <iivanov@suse.de>
Ivan T. Ivanov e55d0f
---
Ivan T. Ivanov e55d0f
 arch/arm64/kernel/entry.S |   22 +++++++++++++---------
Ivan T. Ivanov e55d0f
 1 file changed, 13 insertions(+), 9 deletions(-)
Ivan T. Ivanov e55d0f
Ivan T. Ivanov e55d0f
--- a/arch/arm64/kernel/entry.S
Ivan T. Ivanov e55d0f
+++ b/arch/arm64/kernel/entry.S
Ivan T. Ivanov e55d0f
@@ -568,10 +568,8 @@ el1_sync:
Ivan T. Ivanov e55d0f
 	b.eq	el1_ia
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_SYS64		// configurable trap
Ivan T. Ivanov e55d0f
 	b.eq	el1_undef
Ivan T. Ivanov e55d0f
-	cmp	x24, #ESR_ELx_EC_SP_ALIGN	// stack alignment exception
Ivan T. Ivanov e55d0f
-	b.eq	el1_sp_pc
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_PC_ALIGN	// pc alignment exception
Ivan T. Ivanov e55d0f
-	b.eq	el1_sp_pc
Ivan T. Ivanov e55d0f
+	b.eq	el1_pc
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_UNKNOWN	// unknown exception in EL1
Ivan T. Ivanov e55d0f
 	b.eq	el1_undef
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_BREAKPT_CUR	// debug exception in EL1
Ivan T. Ivanov e55d0f
@@ -593,9 +591,11 @@ el1_da:
Ivan T. Ivanov e55d0f
 	bl	do_mem_abort
Ivan T. Ivanov e55d0f
 
Ivan T. Ivanov e55d0f
 	kernel_exit 1
Ivan T. Ivanov e55d0f
-el1_sp_pc:
Ivan T. Ivanov e55d0f
+el1_pc:
Ivan T. Ivanov e55d0f
 	/*
Ivan T. Ivanov e55d0f
-	 * Stack or PC alignment exception handling
Ivan T. Ivanov e55d0f
+	 * PC alignment exception handling. We don't handle SP alignment faults,
Ivan T. Ivanov e55d0f
+	 * since we will have hit a recursive exception when trying to push the
Ivan T. Ivanov e55d0f
+	 * initial pt_regs.
Ivan T. Ivanov e55d0f
 	 */
Ivan T. Ivanov e55d0f
 	mrs	x0, far_el1
Ivan T. Ivanov e55d0f
 	inherit_daif	pstate=x23, tmp=x2
Ivan T. Ivanov e55d0f
@@ -687,9 +687,9 @@ el0_sync:
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_SYS64		// configurable trap
Ivan T. Ivanov e55d0f
 	b.eq	el0_sys
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_SP_ALIGN	// stack alignment exception
Ivan T. Ivanov e55d0f
-	b.eq	el0_sp_pc
Ivan T. Ivanov e55d0f
+	b.eq	el0_sp
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_PC_ALIGN	// pc alignment exception
Ivan T. Ivanov e55d0f
-	b.eq	el0_sp_pc
Ivan T. Ivanov e55d0f
+	b.eq	el0_pc
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_UNKNOWN	// unknown exception in EL0
Ivan T. Ivanov e55d0f
 	b.eq	el0_undef
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_BREAKPT_LOW	// debug exception in EL0
Ivan T. Ivanov e55d0f
@@ -713,7 +713,7 @@ el0_sync_compat:
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_FP_EXC32	// FP/ASIMD exception
Ivan T. Ivanov e55d0f
 	b.eq	el0_fpsimd_exc
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_PC_ALIGN	// pc alignment exception
Ivan T. Ivanov e55d0f
-	b.eq	el0_sp_pc
Ivan T. Ivanov e55d0f
+	b.eq	el0_pc
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_UNKNOWN	// unknown exception in EL0
Ivan T. Ivanov e55d0f
 	b.eq	el0_undef
Ivan T. Ivanov e55d0f
 	cmp	x24, #ESR_ELx_EC_CP15_32	// CP15 MRC/MCR trap
Ivan T. Ivanov e55d0f
@@ -817,11 +817,15 @@ el0_fpsimd_exc:
Ivan T. Ivanov e55d0f
 	mov	x1, sp
Ivan T. Ivanov e55d0f
 	bl	do_fpsimd_exc
Ivan T. Ivanov e55d0f
 	b	ret_to_user
Ivan T. Ivanov e55d0f
+el0_sp:
Ivan T. Ivanov e55d0f
+	ldr	x26, [sp, #S_SP]
Ivan T. Ivanov e55d0f
+	b	el0_sp_pc
Ivan T. Ivanov e55d0f
+el0_pc:
Ivan T. Ivanov e55d0f
+	mrs	x26, far_el1
Ivan T. Ivanov e55d0f
 el0_sp_pc:
Ivan T. Ivanov e55d0f
 	/*
Ivan T. Ivanov e55d0f
 	 * Stack or PC alignment exception handling
Ivan T. Ivanov e55d0f
 	 */
Ivan T. Ivanov e55d0f
-	mrs	x26, far_el1
Ivan T. Ivanov e55d0f
 	enable_da_f
Ivan T. Ivanov e55d0f
 #ifdef CONFIG_TRACE_IRQFLAGS
Ivan T. Ivanov e55d0f
 	bl	trace_hardirqs_off