arm64: entry: SP Alignment Fault doesn't write to FAR_EL1
authorJames Morse <james.morse@arm.com>
Mon, 22 Jul 2019 15:11:48 +0000 (16:11 +0100)
committerWill Deacon <will@kernel.org>
Mon, 22 Jul 2019 15:22:34 +0000 (16:22 +0100)
Comparing the arm-arm's  pseudocode for AArch64.PCAlignmentFault() with
AArch64.SPAlignmentFault() shows that SP faults don't copy the faulty-SP
to FAR_EL1, but this is where we read from, and the address we provide
to user-space with the BUS_ADRALN signal.

For user-space this value will be UNKNOWN due to the previous ERET to
user-space. If the last value is preserved, on systems with KASLR or KPTI
this will be the user-space link-register left in FAR_EL1 by tramp_exit().
Fix this to retrieve the original sp_el0 value, and pass this to
do_sp_pc_fault().

SP alignment faults from EL1 will cause us to take the fault again when
trying to store the pt_regs. This eventually takes us to the overflow
stack. Remove the ESR_ELx_EC_SP_ALIGN check as we will never make it
this far.

Fixes: 60ffc30d5652 ("arm64: Exception handling")
Signed-off-by: James Morse <james.morse@arm.com>
[will: change label name and fleshed out comment]
Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/kernel/entry.S

index 9cdc4592da3efdbd8f1bd8ade319b094f6e8da4f..320a30dbe35efb02e4f7d5bd52c82189e1f4400c 100644 (file)
@@ -586,10 +586,8 @@ el1_sync:
        b.eq    el1_ia
        cmp     x24, #ESR_ELx_EC_SYS64          // configurable trap
        b.eq    el1_undef
-       cmp     x24, #ESR_ELx_EC_SP_ALIGN       // stack alignment exception
-       b.eq    el1_sp_pc
        cmp     x24, #ESR_ELx_EC_PC_ALIGN       // pc alignment exception
-       b.eq    el1_sp_pc
+       b.eq    el1_pc
        cmp     x24, #ESR_ELx_EC_UNKNOWN        // unknown exception in EL1
        b.eq    el1_undef
        cmp     x24, #ESR_ELx_EC_BREAKPT_CUR    // debug exception in EL1
@@ -611,9 +609,11 @@ el1_da:
        bl      do_mem_abort
 
        kernel_exit 1
-el1_sp_pc:
+el1_pc:
        /*
-        * Stack or PC alignment exception handling
+        * PC alignment exception handling. We don't handle SP alignment faults,
+        * since we will have hit a recursive exception when trying to push the
+        * initial pt_regs.
         */
        mrs     x0, far_el1
        inherit_daif    pstate=x23, tmp=x2
@@ -732,9 +732,9 @@ el0_sync:
        ccmp    x24, #ESR_ELx_EC_WFx, #4, ne
        b.eq    el0_sys
        cmp     x24, #ESR_ELx_EC_SP_ALIGN       // stack alignment exception
-       b.eq    el0_sp_pc
+       b.eq    el0_sp
        cmp     x24, #ESR_ELx_EC_PC_ALIGN       // pc alignment exception
-       b.eq    el0_sp_pc
+       b.eq    el0_pc
        cmp     x24, #ESR_ELx_EC_UNKNOWN        // unknown exception in EL0
        b.eq    el0_undef
        cmp     x24, #ESR_ELx_EC_BREAKPT_LOW    // debug exception in EL0
@@ -758,7 +758,7 @@ el0_sync_compat:
        cmp     x24, #ESR_ELx_EC_FP_EXC32       // FP/ASIMD exception
        b.eq    el0_fpsimd_exc
        cmp     x24, #ESR_ELx_EC_PC_ALIGN       // pc alignment exception
-       b.eq    el0_sp_pc
+       b.eq    el0_pc
        cmp     x24, #ESR_ELx_EC_UNKNOWN        // unknown exception in EL0
        b.eq    el0_undef
        cmp     x24, #ESR_ELx_EC_CP15_32        // CP15 MRC/MCR trap
@@ -858,11 +858,15 @@ el0_fpsimd_exc:
        mov     x1, sp
        bl      do_fpsimd_exc
        b       ret_to_user
+el0_sp:
+       ldr     x26, [sp, #S_SP]
+       b       el0_sp_pc
+el0_pc:
+       mrs     x26, far_el1
 el0_sp_pc:
        /*
         * Stack or PC alignment exception handling
         */
-       mrs     x26, far_el1
        gic_prio_kentry_setup tmp=x0
        enable_da_f
 #ifdef CONFIG_TRACE_IRQFLAGS