| From 4f1192bd1f50f3c5d4ce4c46c5a9d0930516f8a0 Mon Sep 17 00:00:00 2001 |
| From: Will Deacon <will@kernel.org> |
| Date: Sun, 6 Oct 2019 17:58:00 -0700 |
| Subject: [PATCH] panic: ensure preemption is disabled during panic() |
| |
| commit 20bb759a66be52cf4a9ddd17fddaf509e11490cd upstream. |
| |
| Calling 'panic()' on a kernel with CONFIG_PREEMPT=y can leave the |
| calling CPU in an infinite loop, but with interrupts and preemption |
| enabled. From this state, userspace can continue to be scheduled, |
| despite the system being "dead" as far as the kernel is concerned. |
| |
| This is easily reproducible on arm64 when booting with "nosmp" on the |
| command line; a couple of shell scripts print out a periodic "Ping" |
| message whilst another triggers a crash by writing to |
| /proc/sysrq-trigger: |
| |
| | sysrq: Trigger a crash |
| | Kernel panic - not syncing: sysrq triggered crash |
| | CPU: 0 PID: 1 Comm: init Not tainted 5.2.15 #1 |
| | Hardware name: linux,dummy-virt (DT) |
| | Call trace: |
| | dump_backtrace+0x0/0x148 |
| | show_stack+0x14/0x20 |
| | dump_stack+0xa0/0xc4 |
| | panic+0x140/0x32c |
| | sysrq_handle_reboot+0x0/0x20 |
| | __handle_sysrq+0x124/0x190 |
| | write_sysrq_trigger+0x64/0x88 |
| | proc_reg_write+0x60/0xa8 |
| | __vfs_write+0x18/0x40 |
| | vfs_write+0xa4/0x1b8 |
| | ksys_write+0x64/0xf0 |
| | __arm64_sys_write+0x14/0x20 |
| | el0_svc_common.constprop.0+0xb0/0x168 |
| | el0_svc_handler+0x28/0x78 |
| | el0_svc+0x8/0xc |
| | Kernel Offset: disabled |
| | CPU features: 0x0002,24002004 |
| | Memory Limit: none |
| | ---[ end Kernel panic - not syncing: sysrq triggered crash ]--- |
| | Ping 2! |
| | Ping 1! |
| | Ping 1! |
| | Ping 2! |
| |
| The issue can also be triggered on x86 kernels if CONFIG_SMP=n, |
| otherwise local interrupts are disabled in 'smp_send_stop()'. |
| |
| Disable preemption in 'panic()' before re-enabling interrupts. |
| |
| Link: http://lkml.kernel.org/r/20191002123538.22609-1-will@kernel.org |
| Link: https://lore.kernel.org/r/BX1W47JXPMR8.58IYW53H6M5N@dragonstone |
| Signed-off-by: Will Deacon <will@kernel.org> |
| Reported-by: Xogium <contact@xogium.me> |
| Reviewed-by: Kees Cook <keescook@chromium.org> |
| Cc: Russell King <linux@armlinux.org.uk> |
| Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Cc: Ingo Molnar <mingo@redhat.com> |
| Cc: Petr Mladek <pmladek@suse.com> |
| Cc: Feng Tang <feng.tang@intel.com> |
| Cc: <stable@vger.kernel.org> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/kernel/panic.c b/kernel/panic.c |
| index 4d9f55bf7d38..3406a7a31449 100644 |
| --- a/kernel/panic.c |
| +++ b/kernel/panic.c |
| @@ -179,6 +179,7 @@ void panic(const char *fmt, ...) |
| * after setting panic_cpu) from invoking panic() again. |
| */ |
| local_irq_disable(); |
| + preempt_disable_notrace(); |
| |
| /* |
| * It's possible to come here directly from a panic-assertion and |
| -- |
| 2.7.4 |
| |