Skip to content

Commit 2b0eccc

Browse files
Maxim Levitskybonzini
authored andcommitted
KVM: x86: nSVM: deal with L1 hypervisor that intercepts interrupts but lets L2 control them
Fix a corner case in which the L1 hypervisor intercepts interrupts (INTERCEPT_INTR) and either doesn't set virtual interrupt masking (V_INTR_MASKING) or enters a nested guest with EFLAGS.IF disabled prior to the entry. In this case, despite the fact that L1 intercepts the interrupts, KVM still needs to set up an interrupt window to wait before injecting the INTR vmexit. Currently the KVM instead enters an endless loop of 'req_immediate_exit'. Exactly the same issue also happens for SMIs and NMI. Fix this as well. Note that on VMX, this case is impossible as there is only 'vmexit on external interrupts' execution control which either set, in which case both host and guest's EFLAGS.IF are ignored, or not set, in which case no VMexits are delivered. Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> Message-Id: <20220207155447.840194-8-mlevitsk@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 91f673b commit 2b0eccc

File tree

1 file changed

+13
-4
lines changed

1 file changed

+13
-4
lines changed

arch/x86/kvm/svm/svm.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3361,11 +3361,13 @@ static int svm_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
33613361
if (svm->nested.nested_run_pending)
33623362
return -EBUSY;
33633363

3364+
if (svm_nmi_blocked(vcpu))
3365+
return 0;
3366+
33643367
/* An NMI must not be injected into L2 if it's supposed to VM-Exit. */
33653368
if (for_injection && is_guest_mode(vcpu) && nested_exit_on_nmi(svm))
33663369
return -EBUSY;
3367-
3368-
return !svm_nmi_blocked(vcpu);
3370+
return 1;
33693371
}
33703372

33713373
static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu)
@@ -3417,17 +3419,21 @@ bool svm_interrupt_blocked(struct kvm_vcpu *vcpu)
34173419
static int svm_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection)
34183420
{
34193421
struct vcpu_svm *svm = to_svm(vcpu);
3422+
34203423
if (svm->nested.nested_run_pending)
34213424
return -EBUSY;
34223425

3426+
if (svm_interrupt_blocked(vcpu))
3427+
return 0;
3428+
34233429
/*
34243430
* An IRQ must not be injected into L2 if it's supposed to VM-Exit,
34253431
* e.g. if the IRQ arrived asynchronously after checking nested events.
34263432
*/
34273433
if (for_injection && is_guest_mode(vcpu) && nested_exit_on_intr(svm))
34283434
return -EBUSY;
34293435

3430-
return !svm_interrupt_blocked(vcpu);
3436+
return 1;
34313437
}
34323438

34333439
static void svm_enable_irq_window(struct kvm_vcpu *vcpu)
@@ -4158,11 +4164,14 @@ static int svm_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
41584164
if (svm->nested.nested_run_pending)
41594165
return -EBUSY;
41604166

4167+
if (svm_smi_blocked(vcpu))
4168+
return 0;
4169+
41614170
/* An SMI must not be injected into L2 if it's supposed to VM-Exit. */
41624171
if (for_injection && is_guest_mode(vcpu) && nested_exit_on_smi(svm))
41634172
return -EBUSY;
41644173

4165-
return !svm_smi_blocked(vcpu);
4174+
return 1;
41664175
}
41674176

41684177
static int svm_enter_smm(struct kvm_vcpu *vcpu, char *smstate)

0 commit comments

Comments
 (0)