aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/nmi.c
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2011-12-09 03:02:19 -0500
committerSteven Rostedt <rostedt@goodmis.org>2011-12-21 15:38:55 -0500
commit228bdaa95fb830e08b6acd1afd4d2c55093cabfa (patch)
tree11d91c3d9f5b576003a07852fcf31eb2ec53bc39 /arch/x86/kernel/nmi.c
parent3f3c8b8c4b2a34776c3470142a7c8baafcda6eb0 (diff)
x86: Keep current stack in NMI breakpoints
We want to allow NMI handlers to have breakpoints to be able to remove stop_machine from ftrace, kprobes and jump_labels. But if an NMI interrupts a current breakpoint, and then it triggers a breakpoint itself, it will switch to the breakpoint stack and corrupt the data on it for the breakpoint processing that it interrupted. Instead, have the NMI check if it interrupted breakpoint processing by checking if the stack that is currently used is a breakpoint stack. If it is, then load a special IDT that changes the IST for the debug exception to keep the same stack in kernel context. When the NMI is done, it puts it back. This way, if the NMI does trigger a breakpoint, it will keep using the same stack and not stomp on the breakpoint data for the breakpoint it interrupted. Suggested-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'arch/x86/kernel/nmi.c')
-rw-r--r--arch/x86/kernel/nmi.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index e88f37b58ddd..de8d4b333f40 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -408,6 +408,18 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
408dotraplinkage notrace __kprobes void 408dotraplinkage notrace __kprobes void
409do_nmi(struct pt_regs *regs, long error_code) 409do_nmi(struct pt_regs *regs, long error_code)
410{ 410{
411 int update_debug_stack = 0;
412
413 /*
414 * If we interrupted a breakpoint, it is possible that
415 * the nmi handler will have breakpoints too. We need to
416 * change the IDT such that breakpoints that happen here
417 * continue to use the NMI stack.
418 */
419 if (unlikely(is_debug_stack(regs->sp))) {
420 debug_stack_set_zero();
421 update_debug_stack = 1;
422 }
411 nmi_enter(); 423 nmi_enter();
412 424
413 inc_irq_stat(__nmi_count); 425 inc_irq_stat(__nmi_count);
@@ -416,6 +428,9 @@ do_nmi(struct pt_regs *regs, long error_code)
416 default_do_nmi(regs); 428 default_do_nmi(regs);
417 429
418 nmi_exit(); 430 nmi_exit();
431
432 if (unlikely(update_debug_stack))
433 debug_stack_reset();
419} 434}
420 435
421void stop_nmi(void) 436void stop_nmi(void)