* [bug report] KVM: SVM: Set target pCPU during IRTE update if target vCPU is running
@ 2024-07-19 23:55 Dan Carpenter
2024-07-23 19:02 ` Sean Christopherson
0 siblings, 1 reply; 2+ messages in thread
From: Dan Carpenter @ 2024-07-19 23:55 UTC (permalink / raw)
To: Sean Christopherson; +Cc: kvm
Hello Sean Christopherson,
Commit f3cebc75e742 ("KVM: SVM: Set target pCPU during IRTE update if
target vCPU is running") from Aug 8, 2023 (linux-next), leads to the
following Smatch static checker warning:
arch/x86/kvm/svm/avic.c:841 svm_ir_list_add()
error: we previously assumed 'pi->ir_data' could be null (see line 804)
arch/x86/kvm/svm/avic.c
792 static int svm_ir_list_add(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi)
793 {
794 int ret = 0;
795 unsigned long flags;
796 struct amd_svm_iommu_ir *ir;
797 u64 entry;
798
799 /**
800 * In some cases, the existing irte is updated and re-set,
801 * so we need to check here if it's already been * added
802 * to the ir_list.
803 */
804 if (pi->ir_data && (pi->prev_ga_tag != 0)) {
^^^^^^^^^^^
The old code checks for NULL
805 struct kvm *kvm = svm->vcpu.kvm;
806 u32 vcpu_id = AVIC_GATAG_TO_VCPUID(pi->prev_ga_tag);
807 struct kvm_vcpu *prev_vcpu = kvm_get_vcpu_by_id(kvm, vcpu_id);
808 struct vcpu_svm *prev_svm;
809
810 if (!prev_vcpu) {
811 ret = -EINVAL;
812 goto out;
813 }
814
815 prev_svm = to_svm(prev_vcpu);
816 svm_ir_list_del(prev_svm, pi);
817 }
818
819 /**
820 * Allocating new amd_iommu_pi_data, which will get
821 * add to the per-vcpu ir_list.
822 */
823 ir = kzalloc(sizeof(struct amd_svm_iommu_ir), GFP_KERNEL_ACCOUNT);
824 if (!ir) {
825 ret = -ENOMEM;
826 goto out;
827 }
828 ir->data = pi->ir_data;
829
830 spin_lock_irqsave(&svm->ir_list_lock, flags);
831
832 /*
833 * Update the target pCPU for IOMMU doorbells if the vCPU is running.
834 * If the vCPU is NOT running, i.e. is blocking or scheduled out, KVM
835 * will update the pCPU info when the vCPU awkened and/or scheduled in.
836 * See also avic_vcpu_load().
837 */
838 entry = READ_ONCE(*(svm->avic_physical_id_cache));
839 if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK)
840 amd_iommu_update_ga(entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK,
--> 841 true, pi->ir_data);
^^^^^^^^^^^
The patch adds an unchecked dereference. It could be a false positive if
AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK implies that ->ir_data is non-NULL. In
that case could you just send an email saying "this is a false positive" and
I'll ignore this warning going forward.
842
843 list_add(&ir->node, &svm->ir_list);
844 spin_unlock_irqrestore(&svm->ir_list_lock, flags);
845 out:
846 return ret;
847 }
regards,
dan carpenter
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [bug report] KVM: SVM: Set target pCPU during IRTE update if target vCPU is running
2024-07-19 23:55 [bug report] KVM: SVM: Set target pCPU during IRTE update if target vCPU is running Dan Carpenter
@ 2024-07-23 19:02 ` Sean Christopherson
0 siblings, 0 replies; 2+ messages in thread
From: Sean Christopherson @ 2024-07-23 19:02 UTC (permalink / raw)
To: Dan Carpenter; +Cc: kvm, Suravee Suthikulpanit, Joerg Roedel
+Suravee and Joerg
On Fri, Jul 19, 2024, Dan Carpenter wrote:
> Hello Sean Christopherson,
>
> Commit f3cebc75e742 ("KVM: SVM: Set target pCPU during IRTE update if
> target vCPU is running") from Aug 8, 2023 (linux-next), leads to the
> following Smatch static checker warning:
>
> arch/x86/kvm/svm/avic.c:841 svm_ir_list_add()
> error: we previously assumed 'pi->ir_data' could be null (see line 804)
>
> arch/x86/kvm/svm/avic.c
> 792 static int svm_ir_list_add(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi)
> 793 {
> 794 int ret = 0;
> 795 unsigned long flags;
> 796 struct amd_svm_iommu_ir *ir;
> 797 u64 entry;
> 798
> 799 /**
> 800 * In some cases, the existing irte is updated and re-set,
> 801 * so we need to check here if it's already been * added
> 802 * to the ir_list.
> 803 */
> 804 if (pi->ir_data && (pi->prev_ga_tag != 0)) {
> ^^^^^^^^^^^
> The old code checks for NULL
>
> 805 struct kvm *kvm = svm->vcpu.kvm;
> 806 u32 vcpu_id = AVIC_GATAG_TO_VCPUID(pi->prev_ga_tag);
> 807 struct kvm_vcpu *prev_vcpu = kvm_get_vcpu_by_id(kvm, vcpu_id);
> 808 struct vcpu_svm *prev_svm;
> 809
> 810 if (!prev_vcpu) {
> 811 ret = -EINVAL;
> 812 goto out;
> 813 }
> 814
> 815 prev_svm = to_svm(prev_vcpu);
> 816 svm_ir_list_del(prev_svm, pi);
> 817 }
> 818
> 819 /**
> 820 * Allocating new amd_iommu_pi_data, which will get
> 821 * add to the per-vcpu ir_list.
> 822 */
> 823 ir = kzalloc(sizeof(struct amd_svm_iommu_ir), GFP_KERNEL_ACCOUNT);
> 824 if (!ir) {
> 825 ret = -ENOMEM;
> 826 goto out;
> 827 }
> 828 ir->data = pi->ir_data;
> 829
> 830 spin_lock_irqsave(&svm->ir_list_lock, flags);
> 831
> 832 /*
> 833 * Update the target pCPU for IOMMU doorbells if the vCPU is running.
> 834 * If the vCPU is NOT running, i.e. is blocking or scheduled out, KVM
> 835 * will update the pCPU info when the vCPU awkened and/or scheduled in.
> 836 * See also avic_vcpu_load().
> 837 */
> 838 entry = READ_ONCE(*(svm->avic_physical_id_cache));
> 839 if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK)
> 840 amd_iommu_update_ga(entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK,
> --> 841 true, pi->ir_data);
> ^^^^^^^^^^^
> The patch adds an unchecked dereference. It could be a false positive if
> AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK implies that ->ir_data is non-NULL. In
> that case could you just send an email saying "this is a false positive" and
> I'll ignore this warning going forward.
Hmm, yes and no. AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK does kinda sorta gurantee
->ir_data is non-NULL, because avic_vcpu_load() will pass the same pointer to
amd_iommu_update_ga(), i.e. if ->ir_data is NULL, a crash would already have
happened.
However, I don't understand why _this_ code checks for a non-NULL pi->ir_data.
Or rather, I don't understand why that isn't considered a WARN-able failure.
Generally speaking, pi->ir_data is guaranteed to be valid, as the sole caller
checks that setting affinity succeeded:
ret = irq_set_vcpu_affinity(host_irq, &pi);
if (!ret && pi.is_guest_mode)
svm_ir_list_add(svm, &pi);
but there is one path in amd_ir_set_vcpu_affinity() when it returns "success"
but doesn't set ir_data.
static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info)
{
int ret;
struct amd_iommu_pi_data *pi_data = vcpu_info;
struct vcpu_data *vcpu_pi_info = pi_data->vcpu_data;
struct amd_ir_data *ir_data = data->chip_data;
struct irq_2_irte *irte_info = &ir_data->irq_2_irte;
struct iommu_dev_data *dev_data;
if (ir_data->iommu == NULL)
return -EINVAL;
dev_data = search_dev_data(ir_data->iommu, irte_info->devid);
/* Note:
* This device has never been set up for guest mode.
* we should not modify the IRTE
*/
if (!dev_data || !dev_data->use_vapic) <===
return 0;
ir_data->cfg = irqd_cfg(data);
pi_data->ir_data = ir_data;
That seems like it should be an error. And then KVM should WARN if svm_ir_list_add()
is called with a NULL pi->ir_data.
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index b19e8c0f48fa..e08d28f133d3 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -3687,7 +3687,7 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info)
* we should not modify the IRTE
*/
if (!dev_data || !dev_data->use_vapic)
- return 0;
+ return -EINVAL;
ir_data->cfg = irqd_cfg(data);
pi_data->ir_data = ir_data;
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2024-07-23 19:02 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-19 23:55 [bug report] KVM: SVM: Set target pCPU during IRTE update if target vCPU is running Dan Carpenter
2024-07-23 19:02 ` Sean Christopherson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox