x86/nmi: Prevent instruction breakpoints in NMIs

Now that hw_breakpoint tracks kernel instruction breakpoints for us,
this is easy and will have very little performance impact if there
are no kernel instruction breakpoints.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index 18bc9b5..bd7da73 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -492,6 +492,9 @@
 dotraplinkage notrace void
 do_nmi(struct pt_regs *regs, long error_code)
 {
+	bool restore_dr7 = false;
+	unsigned long old_dr7;
+
 	if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) {
 		this_cpu_write(nmi_state, NMI_LATCHED);
 		return;
@@ -500,6 +503,18 @@
 	this_cpu_write(nmi_cr2, read_cr2());
 nmi_restart:
 
+	/*
+	 * Prevent instruction breakpoints from tripping inside NMI code
+	 * that isn't protected by NOKPROBE_SYMBOL.  We need this
+	 * because we cannot return from an instruction breakpoint
+	 * without using IRET.
+	 */
+	if (this_cpu_read(cpu_nmi_kernel_insn_breakpoint_mask)) {
+		get_debugreg(old_dr7, 7);
+		set_debugreg(0, 7);
+		restore_dr7 = true;
+	}
+
 #ifdef CONFIG_X86_64
 	/*
 	 * If we interrupted a breakpoint, it is possible that
@@ -529,6 +544,9 @@
 	}
 #endif
 
+	if (restore_dr7)
+		set_debugreg(old_dr7, 7);
+
 	if (unlikely(this_cpu_read(nmi_cr2) != read_cr2()))
 		write_cr2(this_cpu_read(nmi_cr2));
 	if (this_cpu_dec_return(nmi_state))