Skip to content

Commit a8258ff

Browse files
misalehjoergroedel
authored andcommitted
iommu: debug-pagealloc: Check mapped/unmapped kernel memory
Now, as the page_ext holds count of IOMMU mappings, we can use it to assert that any page allocated/freed is indeed not in the IOMMU. The sanitizer doesn’t protect against mapping/unmapping during this period. However, that’s less harmful as the page is not used by the kernel. Reviewed-by: Samiullah Khawaja <skhawaja@google.com> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Signed-off-by: Mostafa Saleh <smostafa@google.com> Reviewed-by: Pranjal Shrivastava <praan@google.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
1 parent 7e84593 commit a8258ff

3 files changed

Lines changed: 42 additions & 0 deletions

File tree

drivers/iommu/iommu-debug-pagealloc.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/iommu-debug-pagealloc.h>
1010
#include <linux/kernel.h>
1111
#include <linux/page_ext.h>
12+
#include <linux/page_owner.h>
1213

1314
#include "iommu-priv.h"
1415

@@ -73,6 +74,28 @@ static size_t iommu_debug_page_size(struct iommu_domain *domain)
7374
return 1UL << __ffs(domain->pgsize_bitmap);
7475
}
7576

77+
static bool iommu_debug_page_count(const struct page *page)
78+
{
79+
unsigned int ref;
80+
struct page_ext *page_ext = page_ext_get(page);
81+
struct iommu_debug_metadata *d = get_iommu_data(page_ext);
82+
83+
ref = atomic_read(&d->ref);
84+
page_ext_put(page_ext);
85+
return ref != 0;
86+
}
87+
88+
void __iommu_debug_check_unmapped(const struct page *page, int numpages)
89+
{
90+
while (numpages--) {
91+
if (WARN_ON(iommu_debug_page_count(page))) {
92+
pr_warn("iommu: Detected page leak!\n");
93+
dump_page_owner(page);
94+
}
95+
page++;
96+
}
97+
}
98+
7699
void __iommu_debug_map(struct iommu_domain *domain, phys_addr_t phys, size_t size)
77100
{
78101
size_t off, end;

include/linux/iommu-debug-pagealloc.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,20 @@ DECLARE_STATIC_KEY_FALSE(iommu_debug_initialized);
1313

1414
extern struct page_ext_operations page_iommu_debug_ops;
1515

16+
void __iommu_debug_check_unmapped(const struct page *page, int numpages);
17+
18+
static inline void iommu_debug_check_unmapped(const struct page *page, int numpages)
19+
{
20+
if (static_branch_unlikely(&iommu_debug_initialized))
21+
__iommu_debug_check_unmapped(page, numpages);
22+
}
23+
24+
#else
25+
static inline void iommu_debug_check_unmapped(const struct page *page,
26+
int numpages)
27+
{
28+
}
29+
1630
#endif /* CONFIG_IOMMU_DEBUG_PAGEALLOC */
1731

1832
#endif /* __LINUX_IOMMU_DEBUG_PAGEALLOC_H */

include/linux/mm.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <linux/rcuwait.h>
3737
#include <linux/bitmap.h>
3838
#include <linux/bitops.h>
39+
#include <linux/iommu-debug-pagealloc.h>
3940

4041
struct mempolicy;
4142
struct anon_vma;
@@ -4133,12 +4134,16 @@ extern void __kernel_map_pages(struct page *page, int numpages, int enable);
41334134
#ifdef CONFIG_DEBUG_PAGEALLOC
41344135
static inline void debug_pagealloc_map_pages(struct page *page, int numpages)
41354136
{
4137+
iommu_debug_check_unmapped(page, numpages);
4138+
41364139
if (debug_pagealloc_enabled_static())
41374140
__kernel_map_pages(page, numpages, 1);
41384141
}
41394142

41404143
static inline void debug_pagealloc_unmap_pages(struct page *page, int numpages)
41414144
{
4145+
iommu_debug_check_unmapped(page, numpages);
4146+
41424147
if (debug_pagealloc_enabled_static())
41434148
__kernel_map_pages(page, numpages, 0);
41444149
}

0 commit comments

Comments
 (0)