Skip to content

Commit a073672

Browse files
npigginmpe
authored andcommitted
powerpc/64/interrupt: Prevent NMI PMI causing a dangerous warning
NMI PMIs really should not return using the normal interrupt_return function. If such a PMI hits in code returning to user with the context switched to user mode, this warning can fire. This was enough to cause crashes when reproducing on 64s, because another perf interrupt would hit while reporting bug, and that would cause another bug, and so on until smashing the stack. Work around that particular crash for now by just disabling that context warning for PMIs. This is a hack and not a complete fix, there could be other such problems lurking in corners. But it does fix the known crash. Signed-off-by: Nicholas Piggin <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent e59b339 commit a073672

File tree

2 files changed

+16
-3
lines changed

2 files changed

+16
-3
lines changed

arch/powerpc/kernel/exceptions-64e.S

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,13 @@ kernel_dbg_exc:
813813
EXCEPTION_COMMON(0x260)
814814
CHECK_NAPPING()
815815
addi r3,r1,STACK_FRAME_OVERHEAD
816+
/*
817+
* XXX: Returning from performance_monitor_exception taken as a
818+
* soft-NMI (Linux irqs disabled) may be risky to use interrupt_return
819+
* and could cause bugs in return or elsewhere. That case should just
820+
* restore registers and return. There is a workaround for one known
821+
* problem in interrupt_exit_kernel_prepare().
822+
*/
816823
bl performance_monitor_exception
817824
b interrupt_return
818825

arch/powerpc/kernel/interrupt.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,16 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs)
374374
if (regs_is_unrecoverable(regs))
375375
unrecoverable_exception(regs);
376376
/*
377-
* CT_WARN_ON comes here via program_check_exception,
378-
* so avoid recursion.
377+
* CT_WARN_ON comes here via program_check_exception, so avoid
378+
* recursion.
379+
*
380+
* Skip the assertion on PMIs to work around a problem caused by NMI
381+
* PMIs incorrectly taking this interrupt return path, it's possible
382+
* for this to hit after interrupt exit to user switches context to
383+
* user. See also the comment in the performance monitor handler in
384+
* exceptions-64e/s.S
379385
*/
380-
if (TRAP(regs) != INTERRUPT_PROGRAM)
386+
if (TRAP(regs) != INTERRUPT_PROGRAM && TRAP(regs) != INTERRUPT_PERFMON)
381387
CT_WARN_ON(ct_state() == CONTEXT_USER);
382388

383389
kuap = kuap_get_and_assert_locked();

0 commit comments

Comments
 (0)