Skip to content

Commit 74536f9

Browse files
yiliu1765joergroedel
authored andcommitted
iommu/vt-d: Fix qi_batch NULL pointer with nested parent domain
The qi_batch is allocated when assigning cache tag for a domain. While for nested parent domain, it is missed. Hence, when trying to map pages to the nested parent, NULL dereference occurred. Also, there is potential memleak since there is no lock around domain->qi_batch allocation. To solve it, add a helper for qi_batch allocation, and call it in both the __cache_tag_assign_domain() and __cache_tag_assign_parent_domain(). BUG: kernel NULL pointer dereference, address: 0000000000000200 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 8104795067 P4D 0 Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 223 UID: 0 PID: 4357 Comm: qemu-system-x86 Not tainted 6.13.0-rc1-00028-g4b50c3c3b998-dirty #2632 Call Trace: ? __die+0x24/0x70 ? page_fault_oops+0x80/0x150 ? do_user_addr_fault+0x63/0x7b0 ? exc_page_fault+0x7c/0x220 ? asm_exc_page_fault+0x26/0x30 ? cache_tag_flush_range_np+0x13c/0x260 intel_iommu_iotlb_sync_map+0x1a/0x30 iommu_map+0x61/0xf0 batch_to_domain+0x188/0x250 iopt_area_fill_domains+0x125/0x320 ? rcu_is_watching+0x11/0x50 iopt_map_pages+0x63/0x100 iopt_map_common.isra.0+0xa7/0x190 iopt_map_user_pages+0x6a/0x80 iommufd_ioas_map+0xcd/0x1d0 iommufd_fops_ioctl+0x118/0x1c0 __x64_sys_ioctl+0x93/0xc0 do_syscall_64+0x71/0x140 entry_SYSCALL_64_after_hwframe+0x76/0x7e Fixes: 705c1cd ("iommu/vt-d: Introduce batched cache invalidation") Cc: [email protected] Co-developed-by: Lu Baolu <[email protected]> Signed-off-by: Lu Baolu <[email protected]> Signed-off-by: Yi Liu <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 1f2557e commit 74536f9

File tree

1 file changed

+27
-7
lines changed

1 file changed

+27
-7
lines changed

drivers/iommu/intel/cache.c

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,35 @@ static void cache_tag_unassign(struct dmar_domain *domain, u16 did,
105105
spin_unlock_irqrestore(&domain->cache_lock, flags);
106106
}
107107

108+
/* domain->qi_batch will be freed in iommu_free_domain() path. */
109+
static int domain_qi_batch_alloc(struct dmar_domain *domain)
110+
{
111+
unsigned long flags;
112+
int ret = 0;
113+
114+
spin_lock_irqsave(&domain->cache_lock, flags);
115+
if (domain->qi_batch)
116+
goto out_unlock;
117+
118+
domain->qi_batch = kzalloc(sizeof(*domain->qi_batch), GFP_ATOMIC);
119+
if (!domain->qi_batch)
120+
ret = -ENOMEM;
121+
out_unlock:
122+
spin_unlock_irqrestore(&domain->cache_lock, flags);
123+
124+
return ret;
125+
}
126+
108127
static int __cache_tag_assign_domain(struct dmar_domain *domain, u16 did,
109128
struct device *dev, ioasid_t pasid)
110129
{
111130
struct device_domain_info *info = dev_iommu_priv_get(dev);
112131
int ret;
113132

133+
ret = domain_qi_batch_alloc(domain);
134+
if (ret)
135+
return ret;
136+
114137
ret = cache_tag_assign(domain, did, dev, pasid, CACHE_TAG_IOTLB);
115138
if (ret || !info->ats_enabled)
116139
return ret;
@@ -139,6 +162,10 @@ static int __cache_tag_assign_parent_domain(struct dmar_domain *domain, u16 did,
139162
struct device_domain_info *info = dev_iommu_priv_get(dev);
140163
int ret;
141164

165+
ret = domain_qi_batch_alloc(domain);
166+
if (ret)
167+
return ret;
168+
142169
ret = cache_tag_assign(domain, did, dev, pasid, CACHE_TAG_NESTING_IOTLB);
143170
if (ret || !info->ats_enabled)
144171
return ret;
@@ -190,13 +217,6 @@ int cache_tag_assign_domain(struct dmar_domain *domain,
190217
u16 did = domain_get_id_for_dev(domain, dev);
191218
int ret;
192219

193-
/* domain->qi_bach will be freed in iommu_free_domain() path. */
194-
if (!domain->qi_batch) {
195-
domain->qi_batch = kzalloc(sizeof(*domain->qi_batch), GFP_KERNEL);
196-
if (!domain->qi_batch)
197-
return -ENOMEM;
198-
}
199-
200220
ret = __cache_tag_assign_domain(domain, did, dev, pasid);
201221
if (ret || domain->domain.type != IOMMU_DOMAIN_NESTED)
202222
return ret;

0 commit comments

Comments
 (0)