Skip to content

Commit fb7333d

Browse files
committed
KVM: SVM: fix calls to is_intercept
is_intercept takes an INTERCEPT_* constant, not SVM_EXIT_*; because of this, the compiler was removing the body of the conditionals, as if is_intercept returned 0. This unveils a latent bug: when clearing the VINTR intercept, int_ctl must also be changed in the L1 VMCB (svm->nested.hsave), just like the intercept itself is also changed in the L1 VMCB. Otherwise V_IRQ remains set and, due to the VINTR intercept being clear, we get a spurious injection of a vector 0 interrupt on the next L2->L1 vmexit. Reported-by: Qian Cai <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 75ad6e8 commit fb7333d

File tree

2 files changed

+4
-2
lines changed

2 files changed

+4
-2
lines changed

arch/x86/kvm/svm/nested.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ void sync_nested_vmcb_control(struct vcpu_svm *svm)
258258
/* Only a few fields of int_ctl are written by the processor. */
259259
mask = V_IRQ_MASK | V_TPR_MASK;
260260
if (!(svm->nested.ctl.int_ctl & V_INTR_MASKING_MASK) &&
261-
is_intercept(svm, SVM_EXIT_VINTR)) {
261+
is_intercept(svm, INTERCEPT_VINTR)) {
262262
/*
263263
* In order to request an interrupt window, L0 is usurping
264264
* svm->vmcb->control.int_ctl and possibly setting V_IRQ

arch/x86/kvm/svm/svm.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,8 @@ static void svm_clear_vintr(struct vcpu_svm *svm)
13781378
/* Drop int_ctl fields related to VINTR injection. */
13791379
svm->vmcb->control.int_ctl &= mask;
13801380
if (is_guest_mode(&svm->vcpu)) {
1381+
svm->nested.hsave->control.int_ctl &= mask;
1382+
13811383
WARN_ON((svm->vmcb->control.int_ctl & V_TPR_MASK) !=
13821384
(svm->nested.ctl.int_ctl & V_TPR_MASK));
13831385
svm->vmcb->control.int_ctl |= svm->nested.ctl.int_ctl & ~mask;
@@ -1999,7 +2001,7 @@ void svm_set_gif(struct vcpu_svm *svm, bool value)
19992001
*/
20002002
if (vgif_enabled(svm))
20012003
clr_intercept(svm, INTERCEPT_STGI);
2002-
if (is_intercept(svm, SVM_EXIT_VINTR))
2004+
if (is_intercept(svm, INTERCEPT_VINTR))
20032005
svm_clear_vintr(svm);
20042006

20052007
enable_gif(svm);

0 commit comments

Comments
 (0)