Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28696f43 authored by Salman Qazi's avatar Salman Qazi Committed by Steven Rostedt
Browse files

x86: Don't clobber top of pt_regs in nested NMI

The nested NMI modifies the place (instruction, flags and stack)
that the first NMI will iret to.  However, the copy of registers
modified is exactly the one that is the part of pt_regs in
the first NMI.  This can change the behaviour of the first NMI.

In particular, Google's arch_trigger_all_cpu_backtrace handler
also prints regions of memory surrounding addresses appearing in
registers.  This results in handled exceptions, after which nested NMIs
start coming in.  These nested NMIs change the value of registers
in pt_regs.  This can cause the original NMI handler to produce
incorrect output.

We solve this problem by interchanging the position of the preserved
copy of the iret registers ("saved") and the copy subject to being
trampled by nested NMI ("copied").

Link: http://lkml.kernel.org/r/20121002002919.27236.14388.stgit@dungbeetle.mtv.corp.google.com



Signed-off-by: default avatarSalman Qazi <sqazi@google.com>
[ Added a needed CFI_ADJUST_CFA_OFFSET ]
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent 269833bd
Loading
Loading
Loading
Loading
+27 −14
Original line number Original line Diff line number Diff line
@@ -1699,9 +1699,10 @@ nested_nmi:


1:
1:
	/* Set up the interrupted NMIs stack to jump to repeat_nmi */
	/* Set up the interrupted NMIs stack to jump to repeat_nmi */
	leaq -6*8(%rsp), %rdx
	leaq -1*8(%rsp), %rdx
	movq %rdx, %rsp
	movq %rdx, %rsp
	CFI_ADJUST_CFA_OFFSET 6*8
	CFI_ADJUST_CFA_OFFSET 1*8
	leaq -10*8(%rsp), %rdx
	pushq_cfi $__KERNEL_DS
	pushq_cfi $__KERNEL_DS
	pushq_cfi %rdx
	pushq_cfi %rdx
	pushfq_cfi
	pushfq_cfi
@@ -1709,8 +1710,8 @@ nested_nmi:
	pushq_cfi $repeat_nmi
	pushq_cfi $repeat_nmi


	/* Put stack back */
	/* Put stack back */
	addq $(11*8), %rsp
	addq $(6*8), %rsp
	CFI_ADJUST_CFA_OFFSET -11*8
	CFI_ADJUST_CFA_OFFSET -6*8


nested_nmi_out:
nested_nmi_out:
	popq_cfi %rdx
	popq_cfi %rdx
@@ -1736,18 +1737,18 @@ first_nmi:
	 * +-------------------------+
	 * +-------------------------+
	 * | NMI executing variable  |
	 * | NMI executing variable  |
	 * +-------------------------+
	 * +-------------------------+
	 * | Saved SS                |
	 * | Saved Return RSP        |
	 * | Saved RFLAGS            |
	 * | Saved CS                |
	 * | Saved RIP               |
	 * +-------------------------+
	 * | copied SS               |
	 * | copied SS               |
	 * | copied Return RSP       |
	 * | copied Return RSP       |
	 * | copied RFLAGS           |
	 * | copied RFLAGS           |
	 * | copied CS               |
	 * | copied CS               |
	 * | copied RIP              |
	 * | copied RIP              |
	 * +-------------------------+
	 * +-------------------------+
	 * | Saved SS                |
	 * | Saved Return RSP        |
	 * | Saved RFLAGS            |
	 * | Saved CS                |
	 * | Saved RIP               |
	 * +-------------------------+
	 * | pt_regs                 |
	 * | pt_regs                 |
	 * +-------------------------+
	 * +-------------------------+
	 *
	 *
@@ -1763,9 +1764,14 @@ first_nmi:
	/* Set the NMI executing variable on the stack. */
	/* Set the NMI executing variable on the stack. */
	pushq_cfi $1
	pushq_cfi $1


	/*
	 * Leave room for the "copied" frame
	 */
	subq $(5*8), %rsp

	/* Copy the stack frame to the Saved frame */
	/* Copy the stack frame to the Saved frame */
	.rept 5
	.rept 5
	pushq_cfi 6*8(%rsp)
	pushq_cfi 11*8(%rsp)
	.endr
	.endr
	CFI_DEF_CFA_OFFSET SS+8-RIP
	CFI_DEF_CFA_OFFSET SS+8-RIP


@@ -1786,12 +1792,15 @@ repeat_nmi:
	 * is benign for the non-repeat case, where 1 was pushed just above
	 * is benign for the non-repeat case, where 1 was pushed just above
	 * to this very stack slot).
	 * to this very stack slot).
	 */
	 */
	movq $1, 5*8(%rsp)
	movq $1, 10*8(%rsp)


	/* Make another copy, this one may be modified by nested NMIs */
	/* Make another copy, this one may be modified by nested NMIs */
	addq $(10*8), %rsp
	CFI_ADJUST_CFA_OFFSET -10*8
	.rept 5
	.rept 5
	pushq_cfi 4*8(%rsp)
	pushq_cfi -6*8(%rsp)
	.endr
	.endr
	subq $(5*8), %rsp
	CFI_DEF_CFA_OFFSET SS+8-RIP
	CFI_DEF_CFA_OFFSET SS+8-RIP
end_repeat_nmi:
end_repeat_nmi:


@@ -1842,8 +1851,12 @@ nmi_swapgs:
	SWAPGS_UNSAFE_STACK
	SWAPGS_UNSAFE_STACK
nmi_restore:
nmi_restore:
	RESTORE_ALL 8
	RESTORE_ALL 8

	/* Pop the extra iret frame */
	addq $(5*8), %rsp

	/* Clear the NMI executing stack variable */
	/* Clear the NMI executing stack variable */
	movq $0, 10*8(%rsp)
	movq $0, 5*8(%rsp)
	jmp irq_return
	jmp irq_return
	CFI_ENDPROC
	CFI_ENDPROC
END(nmi)
END(nmi)