Skip to content

Commit 9bcac97

Browse files
sean-jcbonzini
authored andcommitted
KVM: x86: Reset IRTE to host control if *new* route isn't postable
Restore an IRTE back to host control (remapped or posted MSI mode) if the *new* GSI route prevents posting the IRQ directly to a vCPU, regardless of the GSI routing type. Updating the IRTE if and only if the new GSI is an MSI results in KVM leaving an IRTE posting to a vCPU. The dangling IRTE can result in interrupts being incorrectly delivered to the guest, and in the worst case scenario can result in use-after-free, e.g. if the VM is torn down, but the underlying host IRQ isn't freed. Fixes: efc6440 ("KVM: x86: Update IRTE for posted-interrupts") Fixes: 411b44b ("svm: Implements update_pi_irte hook to setup posted interrupt") Cc: [email protected] Signed-off-by: Sean Christopherson <[email protected]> Message-ID: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 7537ded commit 9bcac97

File tree

2 files changed

+41
-45
lines changed

2 files changed

+41
-45
lines changed

arch/x86/kvm/svm/avic.c

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,7 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
896896
{
897897
struct kvm_kernel_irq_routing_entry *e;
898898
struct kvm_irq_routing_table *irq_rt;
899+
bool enable_remapped_mode = true;
899900
int idx, ret = 0;
900901

901902
if (!kvm_arch_has_assigned_device(kvm) || !kvm_arch_has_irq_bypass())
@@ -932,6 +933,8 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
932933
kvm_vcpu_apicv_active(&svm->vcpu)) {
933934
struct amd_iommu_pi_data pi;
934935

936+
enable_remapped_mode = false;
937+
935938
/* Try to enable guest_mode in IRTE */
936939
pi.base = __sme_set(page_to_phys(svm->avic_backing_page) &
937940
AVIC_HPA_MASK);
@@ -950,33 +953,6 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
950953
*/
951954
if (!ret && pi.is_guest_mode)
952955
svm_ir_list_add(svm, &pi);
953-
} else {
954-
/* Use legacy mode in IRTE */
955-
struct amd_iommu_pi_data pi;
956-
957-
/**
958-
* Here, pi is used to:
959-
* - Tell IOMMU to use legacy mode for this interrupt.
960-
* - Retrieve ga_tag of prior interrupt remapping data.
961-
*/
962-
pi.prev_ga_tag = 0;
963-
pi.is_guest_mode = false;
964-
ret = irq_set_vcpu_affinity(host_irq, &pi);
965-
966-
/**
967-
* Check if the posted interrupt was previously
968-
* setup with the guest_mode by checking if the ga_tag
969-
* was cached. If so, we need to clean up the per-vcpu
970-
* ir_list.
971-
*/
972-
if (!ret && pi.prev_ga_tag) {
973-
int id = AVIC_GATAG_TO_VCPUID(pi.prev_ga_tag);
974-
struct kvm_vcpu *vcpu;
975-
976-
vcpu = kvm_get_vcpu_by_id(kvm, id);
977-
if (vcpu)
978-
svm_ir_list_del(to_svm(vcpu), &pi);
979-
}
980956
}
981957

982958
if (!ret && svm) {
@@ -992,6 +968,34 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
992968
}
993969

994970
ret = 0;
971+
if (enable_remapped_mode) {
972+
/* Use legacy mode in IRTE */
973+
struct amd_iommu_pi_data pi;
974+
975+
/**
976+
* Here, pi is used to:
977+
* - Tell IOMMU to use legacy mode for this interrupt.
978+
* - Retrieve ga_tag of prior interrupt remapping data.
979+
*/
980+
pi.prev_ga_tag = 0;
981+
pi.is_guest_mode = false;
982+
ret = irq_set_vcpu_affinity(host_irq, &pi);
983+
984+
/**
985+
* Check if the posted interrupt was previously
986+
* setup with the guest_mode by checking if the ga_tag
987+
* was cached. If so, we need to clean up the per-vcpu
988+
* ir_list.
989+
*/
990+
if (!ret && pi.prev_ga_tag) {
991+
int id = AVIC_GATAG_TO_VCPUID(pi.prev_ga_tag);
992+
struct kvm_vcpu *vcpu;
993+
994+
vcpu = kvm_get_vcpu_by_id(kvm, id);
995+
if (vcpu)
996+
svm_ir_list_del(to_svm(vcpu), &pi);
997+
}
998+
}
995999
out:
9961000
srcu_read_unlock(&kvm->irq_srcu, idx);
9971001
return ret;

arch/x86/kvm/vmx/posted_intr.c

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
297297
{
298298
struct kvm_kernel_irq_routing_entry *e;
299299
struct kvm_irq_routing_table *irq_rt;
300+
bool enable_remapped_mode = true;
300301
struct kvm_lapic_irq irq;
301302
struct kvm_vcpu *vcpu;
302303
struct vcpu_data vcpu_info;
@@ -335,40 +336,31 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
335336

336337
kvm_set_msi_irq(kvm, e, &irq);
337338
if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu) ||
338-
!kvm_irq_is_postable(&irq)) {
339-
/*
340-
* Make sure the IRTE is in remapped mode if
341-
* we don't handle it in posted mode.
342-
*/
343-
ret = irq_set_vcpu_affinity(host_irq, NULL);
344-
if (ret < 0) {
345-
printk(KERN_INFO
346-
"failed to back to remapped mode, irq: %u\n",
347-
host_irq);
348-
goto out;
349-
}
350-
339+
!kvm_irq_is_postable(&irq))
351340
continue;
352-
}
353341

354342
vcpu_info.pi_desc_addr = __pa(vcpu_to_pi_desc(vcpu));
355343
vcpu_info.vector = irq.vector;
356344

357345
trace_kvm_pi_irte_update(host_irq, vcpu->vcpu_id, e->gsi,
358346
vcpu_info.vector, vcpu_info.pi_desc_addr, set);
359347

360-
if (set)
361-
ret = irq_set_vcpu_affinity(host_irq, &vcpu_info);
362-
else
363-
ret = irq_set_vcpu_affinity(host_irq, NULL);
348+
if (!set)
349+
continue;
364350

351+
enable_remapped_mode = false;
352+
353+
ret = irq_set_vcpu_affinity(host_irq, &vcpu_info);
365354
if (ret < 0) {
366355
printk(KERN_INFO "%s: failed to update PI IRTE\n",
367356
__func__);
368357
goto out;
369358
}
370359
}
371360

361+
if (enable_remapped_mode)
362+
ret = irq_set_vcpu_affinity(host_irq, NULL);
363+
372364
ret = 0;
373365
out:
374366
srcu_read_unlock(&kvm->irq_srcu, idx);

0 commit comments

Comments
 (0)