[PATCH] amd_iommu: Fix leak in free_pagetable()

From: Alex Williamson
Date: Mon Jun 17 2013 - 21:48:17 EST


AMD IOMMU initializes domains with a 3 level page table by default
and will dynamically size it up to a 6 level page table. Sadly,
free_pagetable() ignores this feature and statically frees as if
it's a 3 level page table. Recurse through all the levels to
free everything.

Signed-off-by: Alex Williamson <alex.williamson@xxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx
---

This is obviously a version rewritten to be recursive. I'll also
post a flat version, take your pick.

drivers/iommu/amd_iommu.c | 36 +++++++++++++++---------------------
1 file changed, 15 insertions(+), 21 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 565c745..5496025 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -1906,32 +1906,26 @@ static void domain_id_free(int id)
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
}

-static void free_pagetable(struct protection_domain *domain)
+static void free_pagetable_level(int level, int max_level, u64 *pt)
{
- int i, j;
- u64 *p1, *p2, *p3;
+ if (level < max_level) {
+ int i;
+ for (i = 0; i < 512; ++i) {
+ if (IOMMU_PTE_PRESENT(pt[i]))
+ free_pagetable_level(level + 1, max_level,
+ IOMMU_PTE_PAGE(pt[i]));
+ }
+ }

- p1 = domain->pt_root;
+ free_page((unsigned long)pt);
+}

- if (!p1)
+static void free_pagetable(struct protection_domain *domain)
+{
+ if (!domain->pt_root)
return;

- for (i = 0; i < 512; ++i) {
- if (!IOMMU_PTE_PRESENT(p1[i]))
- continue;
-
- p2 = IOMMU_PTE_PAGE(p1[i]);
- for (j = 0; j < 512; ++j) {
- if (!IOMMU_PTE_PRESENT(p2[j]))
- continue;
- p3 = IOMMU_PTE_PAGE(p2[j]);
- free_page((unsigned long)p3);
- }
-
- free_page((unsigned long)p2);
- }
-
- free_page((unsigned long)p1);
+ free_pagetable_level(PAGE_MODE_1_LEVEL, domain->mode, domain->pt_root);

domain->pt_root = NULL;
}

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/