aboutsummaryrefslogtreecommitdiff
path: root/arch/riscv/kernel
diff options
context:
space:
mode:
authorMattias Nissler2023-02-15 14:48:28 +0000
committerGreg Kroah-Hartman2023-03-10 09:34:29 +0100
commit3e92e7fa24acd0775e6b4588b0b8d973e5b07bf3 (patch)
tree0d8dadbb0c61a7c4db747daa39376d90f2932789 /arch/riscv/kernel
parenta1f8e698148856dc1dd08f86afb1dee78e6b2e09 (diff)
riscv: Avoid enabling interrupts in die()
commit 130aee3fd9981297ff9354e5d5609cd59aafbbea upstream. While working on something else, I noticed that the kernel would start accepting interrupts again after crashing in an interrupt handler. Since the kernel is already in inconsistent state, enabling interrupts is dangerous and opens up risk of kernel state deteriorating further. Interrupts do get enabled via what looks like an unintended side effect of spin_unlock_irq, so switch to the more cautious spin_lock_irqsave/spin_unlock_irqrestore instead. Fixes: 76d2a0493a17 ("RISC-V: Init and Halt Code") Signed-off-by: Mattias Nissler <mnissler@rivosinc.com> Reviewed-by: Björn Töpel <bjorn@kernel.org> Link: https://lore.kernel.org/r/20230215144828.3370316-1-mnissler@rivosinc.com Cc: stable@vger.kernel.org Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch/riscv/kernel')
-rw-r--r--arch/riscv/kernel/traps.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
index f77cb8e42bd2..5d07f6b3ca32 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -34,10 +34,11 @@ void die(struct pt_regs *regs, const char *str)
static int die_counter;
int ret;
long cause;
+ unsigned long flags;
oops_enter();
- spin_lock_irq(&die_lock);
+ spin_lock_irqsave(&die_lock, flags);
console_verbose();
bust_spinlocks(1);
@@ -54,7 +55,7 @@ void die(struct pt_regs *regs, const char *str)
bust_spinlocks(0);
add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
- spin_unlock_irq(&die_lock);
+ spin_unlock_irqrestore(&die_lock, flags);
oops_exit();
if (in_interrupt())