ANDROID: iommu/arm-smmu-v3-kvm: Fix accidental domain ID freeing in free()

kvm_arm_smmu_domain_finalize() always sets a domain's smmu field, even
if the function fails. If the function fails and the caller attempts
to free the domain, the kvm_arm_smmu_domain_free() function will be
called. The will domain's smmu field is not NULL, so the logic will
call into the hypervisor to free the domain, and free the domain
ID back to the IDA.

However, it's possible that the domain was not even allocated to begin
with in the hypervisor, or the domain ID was not allocated either,
hence why kvm_arm_smmu_domain_finalize() failed in the first place.

Change kvm_arm_smmu_domain_finalize() to only set the smmu field
if it succeeded to allocate all resources required. That way, the
free() callback has meaningful objects to free.

Bug: 423086309
Change-Id: Ib22bbf15b2f3649fc42d7788a17b8e25b8bd2777
Signed-off-by: Isaac J. Manjarres <isaacmanjarres@google.com>
This commit is contained in:
Isaac J. Manjarres
2025-06-07 01:28:15 +00:00
committed by Treehugger Robot
parent 9733cd1fa2
commit fe02cfa135

View File

@@ -284,15 +284,13 @@ static int kvm_arm_smmu_domain_finalize(struct kvm_arm_smmu_domain *kvm_smmu_dom
return 0; return 0;
} }
kvm_smmu_domain->smmu = smmu;
if (kvm_smmu_domain->domain.type == IOMMU_DOMAIN_IDENTITY) { if (kvm_smmu_domain->domain.type == IOMMU_DOMAIN_IDENTITY) {
kvm_smmu_domain->id = KVM_IOMMU_DOMAIN_IDMAP_ID; kvm_smmu_domain->id = KVM_IOMMU_DOMAIN_IDMAP_ID;
/* /*
* Identity domains doesn't use the DMA API, so no need to * Identity domains doesn't use the DMA API, so no need to
* set the domain aperture. * set the domain aperture.
*/ */
return 0; goto out;
} }
/* Default to stage-1. */ /* Default to stage-1. */
@@ -325,7 +323,13 @@ static int kvm_arm_smmu_domain_finalize(struct kvm_arm_smmu_domain *kvm_smmu_dom
ret = kvm_call_hyp_nvhe_mc(__pkvm_host_iommu_alloc_domain, ret = kvm_call_hyp_nvhe_mc(__pkvm_host_iommu_alloc_domain,
kvm_smmu_domain->id, kvm_smmu_domain->type); kvm_smmu_domain->id, kvm_smmu_domain->type);
if (ret) {
ida_free(&kvm_arm_smmu_domain_ida, kvm_smmu_domain->id);
return ret;
}
out:
kvm_smmu_domain->smmu = smmu;
return ret; return ret;
} }