From fe02cfa1351f2b5e1b498eb2ffc4472cd77c1432 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Sat, 7 Jun 2025 01:28:15 +0000 Subject: [PATCH] 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 --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kvm.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kvm.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kvm.c index 4d32b9d5320e..315b1b17aaa0 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kvm.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kvm.c @@ -284,15 +284,13 @@ static int kvm_arm_smmu_domain_finalize(struct kvm_arm_smmu_domain *kvm_smmu_dom return 0; } - kvm_smmu_domain->smmu = smmu; - if (kvm_smmu_domain->domain.type == IOMMU_DOMAIN_IDENTITY) { kvm_smmu_domain->id = KVM_IOMMU_DOMAIN_IDMAP_ID; /* * Identity domains doesn't use the DMA API, so no need to * set the domain aperture. */ - return 0; + goto out; } /* 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, 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; }