diff options
Diffstat (limited to 'drivers/vfio')
-rw-r--r-- | drivers/vfio/vfio_iommu_spapr_tce.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index b95fa2b64680..735b308709e5 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c | |||
@@ -47,6 +47,16 @@ struct tce_container { | |||
47 | bool enabled; | 47 | bool enabled; |
48 | }; | 48 | }; |
49 | 49 | ||
50 | static bool tce_page_is_contained(struct page *page, unsigned page_shift) | ||
51 | { | ||
52 | /* | ||
53 | * Check that the TCE table granularity is not bigger than the size of | ||
54 | * a page we just found. Otherwise the hardware can get access to | ||
55 | * a bigger memory chunk that it should. | ||
56 | */ | ||
57 | return (PAGE_SHIFT + compound_order(compound_head(page))) >= page_shift; | ||
58 | } | ||
59 | |||
50 | static int tce_iommu_enable(struct tce_container *container) | 60 | static int tce_iommu_enable(struct tce_container *container) |
51 | { | 61 | { |
52 | int ret = 0; | 62 | int ret = 0; |
@@ -189,6 +199,12 @@ static long tce_iommu_build(struct tce_container *container, | |||
189 | ret = -EFAULT; | 199 | ret = -EFAULT; |
190 | break; | 200 | break; |
191 | } | 201 | } |
202 | |||
203 | if (!tce_page_is_contained(page, tbl->it_page_shift)) { | ||
204 | ret = -EPERM; | ||
205 | break; | ||
206 | } | ||
207 | |||
192 | hva = (unsigned long) page_address(page) + offset; | 208 | hva = (unsigned long) page_address(page) + offset; |
193 | 209 | ||
194 | ret = iommu_tce_build(tbl, entry + i, hva, direction); | 210 | ret = iommu_tce_build(tbl, entry + i, hva, direction); |