Commit 5c34c403 authored by Joerg Roedel's avatar Joerg Roedel

iommu/amd: Fix memory leak in free_pagetable

The IOMMU pagetables can have up to 6 levels, but the code
in free_pagetable() only releases the first 3 levels. Fix
this leak by releasing all levels.
Reported-by: default avatarAlex Williamson <alex.williamson@redhat.com>
Signed-off-by: default avatarJoerg Roedel <joro@8bytes.org>
Reviewed-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent 7d132055
...@@ -1893,34 +1893,59 @@ static void domain_id_free(int id) ...@@ -1893,34 +1893,59 @@ static void domain_id_free(int id)
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
} }
#define DEFINE_FREE_PT_FN(LVL, FN) \
static void free_pt_##LVL (unsigned long __pt) \
{ \
unsigned long p; \
u64 *pt; \
int i; \
\
pt = (u64 *)__pt; \
\
for (i = 0; i < 512; ++i) { \
if (!IOMMU_PTE_PRESENT(pt[i])) \
continue; \
\
p = (unsigned long)IOMMU_PTE_PAGE(pt[i]); \
FN(p); \
} \
free_page((unsigned long)pt); \
}
DEFINE_FREE_PT_FN(l2, free_page)
DEFINE_FREE_PT_FN(l3, free_pt_l2)
DEFINE_FREE_PT_FN(l4, free_pt_l3)
DEFINE_FREE_PT_FN(l5, free_pt_l4)
DEFINE_FREE_PT_FN(l6, free_pt_l5)
static void free_pagetable(struct protection_domain *domain) static void free_pagetable(struct protection_domain *domain)
{ {
int i, j; unsigned long root = (unsigned long)domain->pt_root;
u64 *p1, *p2, *p3;
p1 = domain->pt_root;
if (!p1)
return;
for (i = 0; i < 512; ++i) {
if (!IOMMU_PTE_PRESENT(p1[i]))
continue;
p2 = IOMMU_PTE_PAGE(p1[i]); switch (domain->mode) {
for (j = 0; j < 512; ++j) { case PAGE_MODE_NONE:
if (!IOMMU_PTE_PRESENT(p2[j])) break;
continue; case PAGE_MODE_1_LEVEL:
p3 = IOMMU_PTE_PAGE(p2[j]); free_page(root);
free_page((unsigned long)p3); break;
} case PAGE_MODE_2_LEVEL:
free_pt_l2(root);
free_page((unsigned long)p2); break;
case PAGE_MODE_3_LEVEL:
free_pt_l3(root);
break;
case PAGE_MODE_4_LEVEL:
free_pt_l4(root);
break;
case PAGE_MODE_5_LEVEL:
free_pt_l5(root);
break;
case PAGE_MODE_6_LEVEL:
free_pt_l6(root);
break;
default:
BUG();
} }
free_page((unsigned long)p1);
domain->pt_root = NULL;
} }
static void free_gcr3_tbl_level1(u64 *tbl) static void free_gcr3_tbl_level1(u64 *tbl)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment