Commit 9146aa83 authored by Andy Lutomirski's avatar Andy Lutomirski Committed by Kamal Mostafa

x86/nmi/64: Reorder nested NMI checks

commit a27507ca upstream.

Check the repeat_nmi .. end_repeat_nmi special case first.  The next
patch will rework the RSP check and, as a side effect, the RSP check
will no longer detect repeat_nmi .. end_repeat_nmi, so we'll need
this ordering of the checks.

Note: this is more subtle than it appears.  The check for repeat_nmi
.. end_repeat_nmi jumps straight out of the NMI code instead of
adjusting the "iret" frame to force a repeat.  This is necessary,
because the code between repeat_nmi and end_repeat_nmi sets "NMI
executing" and then writes to the "iret" frame itself.  If a nested
NMI comes in and modifies the "iret" frame while repeat_nmi is also
modifying it, we'll end up with garbage.  The old code got this
right, as does the new code, but the new code is a bit more
explicit.

If we were to move the check right after the "NMI executing" check,
then we'd get it wrong and have random crashes.

This is a prerequisite for the fix for CVE-2015-3291.
Signed-off-by: default avatarAndy Lutomirski <luto@kernel.org>
[bwh: Backported to 4.0: adjust filename, spacing]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
Acked-by: default avatarJohn Johansen <john.johansen@canonical.com>
Acked-by: default avatarAndy Whitcroft <apw@canonical.com>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
Signed-off-by: default avatarAndy Whitcroft <apw@canonical.com>
Signed-off-by: default avatarKamal Mostafa <kamal@canonical.com>
parent 8978aab3
......@@ -1869,7 +1869,24 @@ ENTRY(nmi)
/*
* Determine whether we're a nested NMI.
*
* First check "NMI executing". If it's set, then we're nested.
* If we interrupted kernel code between repeat_nmi and
* end_repeat_nmi, then we are a nested NMI. We must not
* modify the "iret" frame because it's being written by
* the outer NMI. That's okay: the outer NMI handler is
* about to about to call do_nmi anyway, so we can just
* resume the outer NMI.
*/
movq $repeat_nmi, %rdx
cmpq 8(%rsp), %rdx
ja 1f
movq $end_repeat_nmi, %rdx
cmpq 8(%rsp), %rdx
ja nested_nmi_out
1:
/*
* Now check "NMI executing". If it's set, then we're nested.
* This will not detect if we interrupted an outer NMI just
* before IRET.
*/
......@@ -1895,21 +1912,6 @@ ENTRY(nmi)
CFI_REMEMBER_STATE
nested_nmi:
/*
* If we interrupted an NMI that is between repeat_nmi and
* end_repeat_nmi, then we must not modify the "iret" frame
* because it's being written by the outer NMI. That's okay:
* the outer NMI handler is about to call do_nmi anyway,
* so we can just resume the outer NMI.
*/
movq $repeat_nmi, %rdx
cmpq 8(%rsp), %rdx
ja 1f
movq $end_repeat_nmi, %rdx
cmpq 8(%rsp), %rdx
ja nested_nmi_out
1:
/*
* Modify the "iret" frame to point to repeat_nmi, forcing another
* iteration of NMI handling.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment