KVM: arm64: Disassociate vcpus from redistributor region on teardown
authorMarc Zyngier <maz@kernel.org>
Wed, 5 Jun 2024 17:56:37 +0000 (18:56 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jun 2024 11:49:11 +0000 (13:49 +0200)
commit 0d92e4a7ffd5c42b9fa864692f82476c0bf8bcc8 upstream.

When tearing down a redistributor region, make sure we don't have
any dangling pointer to that region stored in a vcpu.

Fixes: e5a35635464b ("kvm: arm64: vgic-v3: Introduce vgic_v3_free_redist_region()")
Reported-by: Alexander Potapenko <glider@google.com>
Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20240605175637.1635653-1-maz@kernel.org
Cc: stable@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/arm64/kvm/vgic/vgic-init.c
arch/arm64/kvm/vgic/vgic-mmio-v3.c
arch/arm64/kvm/vgic/vgic.h

index e949e1d0fd9f7ba80d3a1e5d6cda02354dfe0403..a2b439ad387c805e4b687b73171e2ccfedd949a9 100644 (file)
@@ -355,7 +355,7 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm)
 
        if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
                list_for_each_entry_safe(rdreg, next, &dist->rd_regions, list)
-                       vgic_v3_free_redist_region(rdreg);
+                       vgic_v3_free_redist_region(kvm, rdreg);
                INIT_LIST_HEAD(&dist->rd_regions);
        } else {
                dist->vgic_cpu_base = VGIC_ADDR_UNDEF;
index ae5a3a717655e212c9f9b93e6db9a9b36beec5a9..48e8b60ff1e33821e17a04c14a348770a05b9d41 100644 (file)
@@ -942,8 +942,19 @@ free:
        return ret;
 }
 
-void vgic_v3_free_redist_region(struct vgic_redist_region *rdreg)
+void vgic_v3_free_redist_region(struct kvm *kvm, struct vgic_redist_region *rdreg)
 {
+       struct kvm_vcpu *vcpu;
+       unsigned long c;
+
+       lockdep_assert_held(&kvm->arch.config_lock);
+
+       /* Garbage collect the region */
+       kvm_for_each_vcpu(c, vcpu, kvm) {
+               if (vcpu->arch.vgic_cpu.rdreg == rdreg)
+                       vcpu->arch.vgic_cpu.rdreg = NULL;
+       }
+
        list_del(&rdreg->list);
        kfree(rdreg);
 }
@@ -968,7 +979,7 @@ int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count)
 
                mutex_lock(&kvm->arch.config_lock);
                rdreg = vgic_v3_rdist_region_from_index(kvm, index);
-               vgic_v3_free_redist_region(rdreg);
+               vgic_v3_free_redist_region(kvm, rdreg);
                mutex_unlock(&kvm->arch.config_lock);
                return ret;
        }
index 8d134569d0a1f6c26f9a4735aa0c89847d9add48..fae2618da720b91b25671c6931cfdc2976794274 100644 (file)
@@ -310,7 +310,7 @@ vgic_v3_rd_region_size(struct kvm *kvm, struct vgic_redist_region *rdreg)
 
 struct vgic_redist_region *vgic_v3_rdist_region_from_index(struct kvm *kvm,
                                                           u32 index);
-void vgic_v3_free_redist_region(struct vgic_redist_region *rdreg);
+void vgic_v3_free_redist_region(struct kvm *kvm, struct vgic_redist_region *rdreg);
 
 bool vgic_v3_rdist_overlap(struct kvm *kvm, gpa_t base, size_t size);