aboutsummaryrefslogtreecommitdiffstats
path: root/arch/riscv/kernel/traps.c
diff options
context:
space:
mode:
authorPalmer Dabbelt <palmer@rivosinc.com>2022-12-01 11:38:39 -0800
committerPalmer Dabbelt <palmer@rivosinc.com>2022-12-01 11:38:39 -0800
commit39cefc5f6cd25d555e0455b24810e9aff365b8d6 (patch)
tree3f5ae903747a2bec6fab24ea9de151ddbdf766cf /arch/riscv/kernel/traps.c
parentd556a9aeb62a6cd44aa05aeadcc48245da0a1939 (diff)
parent7e1864332fbc1b993659eab7974da9fe8bf8c128 (diff)
downloadlinux-39cefc5f6cd25d555e0455b24810e9aff365b8d6.tar.gz
RISC-V: Fix a race condition during kernel stack overflow
This fixes a concrete bug but is also the basis for some cleanup work, so I'm merging it based on the offending commit in order to minimize future conflicts. * commit '7e1864332fbc1b993659eab7974da9fe8bf8c128': riscv: fix race when vmap stack overflow
Diffstat (limited to 'arch/riscv/kernel/traps.c')
-rw-r--r--arch/riscv/kernel/traps.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
index f3e96d60a2ff..7abd8e4c4df6 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -221,11 +221,29 @@ asmlinkage unsigned long get_overflow_stack(void)
OVERFLOW_STACK_SIZE;
}
+/*
+ * A pseudo spinlock to protect the shadow stack from being used by multiple
+ * harts concurrently. This isn't a real spinlock because the lock side must
+ * be taken without a valid stack and only a single register, it's only taken
+ * while in the process of panicing anyway so the performance and error
+ * checking a proper spinlock gives us doesn't matter.
+ */
+unsigned long spin_shadow_stack;
+
asmlinkage void handle_bad_stack(struct pt_regs *regs)
{
unsigned long tsk_stk = (unsigned long)current->stack;
unsigned long ovf_stk = (unsigned long)this_cpu_ptr(overflow_stack);
+ /*
+ * We're done with the shadow stack by this point, as we're on the
+ * overflow stack. Tell any other concurrent overflowing harts that
+ * they can proceed with panicing by releasing the pseudo-spinlock.
+ *
+ * This pairs with an amoswap.aq in handle_kernel_stack_overflow.
+ */
+ smp_store_release(&spin_shadow_stack, 0);
+
console_verbose();
pr_emerg("Insufficient stack space to handle exception!\n");