x86/svm: Write the correct %eip into the outgoing task
authorAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 21 Nov 2019 17:22:52 +0000 (17:22 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 28 Nov 2019 17:14:38 +0000 (17:14 +0000)
commit1d758bc6d1a8c0f658a874470c349ee4e27aee46
treeb9809d4c65f6435bcc9dd297d2b72c3237112a82
parente2585f8c2e0d43d350503ff2b2be252adc6b7239
x86/svm: Write the correct %eip into the outgoing task

The TASK_SWITCH vmexit has fault semantics, and doesn't provide any NRIPs
assistance with instruction length.  As a result, any instruction-induced task
switch has the outgoing task's %eip pointing at the instruction switch caused
the switch, rather than after it.

This causes callers of task gates to livelock (repeatedly execute the call/jmp
to enter the task), and any restartable task to become a nop after its first
use (the (re)entry state points at the iret used to exit the task).

32bit Windows in particular is known to use task gates for NMI handling, and
to use NMI IPIs.

In the task switch handler, distinguish instruction-induced from
interrupt/exception-induced task switches, and decode the instruction under
%rip to calculate its length.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Release-acked-by: Juergen Gross <jgross@suse.com>
xen/arch/x86/hvm/svm/emulate.c
xen/arch/x86/hvm/svm/svm.c
xen/include/asm-x86/hvm/svm/emulate.h