Skip to content

Commit 4984563

Browse files
committed
KVM: nVMX: Emulate NOPs in L2, and PAUSE if it's not intercepted
Extend VMX's nested intercept logic for emulated instructions to handle "pause" interception, in quotes because KVM's emulator doesn't filter out NOPs when checking for nested intercepts. Failure to allow emulation of NOPs results in KVM injecting a #UD into L2 on any NOP that collides with the emulator's definition of PAUSE, i.e. on all single-byte NOPs. For PAUSE itself, honor L1's PAUSE-exiting control, but ignore PLE to avoid unnecessarily injecting a #UD into L2. Per the SDM, the first execution of PAUSE after VM-Entry is treated as the beginning of a new loop, i.e. will never trigger a PLE VM-Exit, and so L1 can't expect any given execution of PAUSE to deterministically exit. ... the processor considers this execution to be the first execution of PAUSE in a loop. (It also does so for the first execution of PAUSE at CPL 0 after VM entry.) All that said, the PLE side of things is currently a moot point, as KVM doesn't expose PLE to L1. Note, vmx_check_intercept() is still wildly broken when L1 wants to intercept an instruction, as KVM injects a #UD instead of synthesizing a nested VM-Exit. That issue extends far beyond NOP/PAUSE and needs far more effort to fix, i.e. is a problem for the future. Fixes: 07721fe ("KVM: nVMX: Don't emulate instructions in guest mode") Cc: Mathias Krause <minipli@grsecurity.net> Cc: stable@vger.kernel.org Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Link: https://lore.kernel.org/r/20230405002359.418138-1-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 548bd27 commit 4984563

1 file changed

Lines changed: 15 additions & 0 deletions

File tree

arch/x86/kvm/vmx/vmx.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7935,6 +7935,21 @@ static int vmx_check_intercept(struct kvm_vcpu *vcpu,
79357935
/* FIXME: produce nested vmexit and return X86EMUL_INTERCEPTED. */
79367936
break;
79377937

7938+
case x86_intercept_pause:
7939+
/*
7940+
* PAUSE is a single-byte NOP with a REPE prefix, i.e. collides
7941+
* with vanilla NOPs in the emulator. Apply the interception
7942+
* check only to actual PAUSE instructions. Don't check
7943+
* PAUSE-loop-exiting, software can't expect a given PAUSE to
7944+
* exit, i.e. KVM is within its rights to allow L2 to execute
7945+
* the PAUSE.
7946+
*/
7947+
if ((info->rep_prefix != REPE_PREFIX) ||
7948+
!nested_cpu_has2(vmcs12, CPU_BASED_PAUSE_EXITING))
7949+
return X86EMUL_CONTINUE;
7950+
7951+
break;
7952+
79387953
/* TODO: check more intercepts... */
79397954
default:
79407955
break;

0 commit comments

Comments
 (0)