From: Jiang Liu Date: Mon, 6 Jan 2014 06:18:22 +0000 (+0800) Subject: iommu/vt-d: fix access after free issue in function free_dmar_iommu() X-Git-Tag: firefly_0821_release~176^2~4526^2^3~5 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=5ced12af691771a424fc3bcabecd668025517ebd;p=firefly-linux-kernel-4.4.55.git iommu/vt-d: fix access after free issue in function free_dmar_iommu() Function free_dmar_iommu() may access domain->iommu_lock by spin_unlock_irqrestore(&domain->iommu_lock, flags); after freeing corresponding domain structure. Sample stack dump: [ 8.912818] ========================= [ 8.917072] [ BUG: held lock freed! ] [ 8.921335] 3.13.0-rc1-gerry+ #12 Not tainted [ 8.926375] ------------------------- [ 8.930629] swapper/0/1 is freeing memory ffff880c23b56040-ffff880c23b5613f, with a lock still held there! [ 8.941675] (&(&domain->iommu_lock)->rlock){......}, at: [] init_dmars+0x72c/0x95b [ 8.952582] 1 lock held by swapper/0/1: [ 8.957031] #0: (&(&domain->iommu_lock)->rlock){......}, at: [] init_dmars+0x72c/0x95b [ 8.968487] [ 8.968487] stack backtrace: [ 8.973602] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.13.0-rc1-gerry+ #12 [ 8.981556] Hardware name: Intel Corporation LH Pass ........../SVRBD-ROW_T, BIOS SE5C600.86B.99.99.x059.091020121352 09/10/2012 [ 8.994742] ffff880c23b56040 ffff88042dd33c98 ffffffff815617fd ffff88042dd38b28 [ 9.003566] ffff88042dd33cd0 ffffffff810a977a ffff880c23b56040 0000000000000086 [ 9.012403] ffff88102c4923c0 ffff88042ddb4800 ffffffff81b1e8c0 ffff88042dd33d28 [ 9.021240] Call Trace: [ 9.024138] [] dump_stack+0x4d/0x66 [ 9.030057] [] debug_check_no_locks_freed+0x15a/0x160 [ 9.037723] [] kmem_cache_free+0x62/0x5b0 [ 9.044225] [] domain_exit+0x197/0x1c0 [ 9.050418] [] init_dmars+0x758/0x95b [ 9.056527] [] intel_iommu_init+0x351/0x438 [ 9.063207] [] ? iommu_setup+0x27d/0x27d [ 9.069601] [] pci_iommu_init+0x28/0x52 [ 9.075910] [] do_one_initcall+0x122/0x180 [ 9.082509] [] ? parse_args+0x1e8/0x320 [ 9.088815] [] kernel_init_freeable+0x1e1/0x26c [ 9.095895] [] ? do_early_param+0x88/0x88 [ 9.102396] [] ? rest_init+0xd0/0xd0 [ 9.108410] [] kernel_init+0xe/0x130 [ 9.114423] [] ret_from_fork+0x7c/0xb0 [ 9.120612] [] ? rest_init+0xd0/0xd0 Signed-off-by: Jiang Liu Signed-off-by: Joerg Roedel --- diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index fd9e369a8cf7..dec715c7e525 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1268,7 +1268,7 @@ static void vm_domain_exit(struct dmar_domain *domain); static void free_dmar_iommu(struct intel_iommu *iommu) { struct dmar_domain *domain; - int i; + int i, count; unsigned long flags; if ((iommu->domains) && (iommu->domain_ids)) { @@ -1277,13 +1277,14 @@ static void free_dmar_iommu(struct intel_iommu *iommu) clear_bit(i, iommu->domain_ids); spin_lock_irqsave(&domain->iommu_lock, flags); - if (--domain->iommu_count == 0) { + count = --domain->iommu_count; + spin_unlock_irqrestore(&domain->iommu_lock, flags); + if (count == 0) { if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) vm_domain_exit(domain); else domain_exit(domain); } - spin_unlock_irqrestore(&domain->iommu_lock, flags); } }