iommu/io-pgtable-arm-v7s: Abort allocation when table address overflows the PTE
Subsystems (2)
PATCH 1/1 iommu/io-pgtable-arm-v7s: Abort allocation when table address overflows the PTE
When run on a 64-bit system in selftest, the v7s driver may obtain page table with physical addresses larger than 32-bit. Level-2 tables are 1KB and are are allocated with slab, which doesn't accept the GFP_DMA32 flag. Currently map() truncates the address written in the PTE, causing iova_to_phys() or unmap() to access invalid memory. Kasan reports it as a use-after-free. To avoid any nasty surprise, test if the physical address fits in a PTE before returning a new table. 32-bit systems, which are the main users of this page table format, shouldn't see any difference.
--- drivers/iommu/io-pgtable-arm-v7s.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/iommu/io-pgtable-arm-v7s.c +6 -1
@@ -192,6 +192,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, {struct io_pgtable_cfg *cfg = &data->iop.cfg;struct device *dev = cfg->iommu_dev; +phys_addr_t phys;dma_addr_t dma;size_t size =ARM_V7S_TABLE_SIZE (lvl);void *table =NULL ;
@@ -200,6 +201,10 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, table = (void *)__get_dma_pages (__GFP_ZERO,get_order (size)); else if (lvl == 2) table =kmem_cache_zalloc (data->l2_tables, gfp |GFP_DMA ); + phys =virt_to_phys (table); +if (phys != (arm_v7s_iopte )phys) +/* Doesn't fit in PTE */ + goto out_free;if (table && !(cfg->quirks &IO_PGTABLE_QUIRK_NO_DMA )) { dma =dma_map_single (dev, table, size,DMA_TO_DEVICE );if (dma_mapping_error (dev, dma))
@@ -209,7 +214,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp,* address directly, so if the DMA layer suggests otherwise by * translating or truncating them, that bodes very badly... */ -if (dma !=virt_to_phys (table)) +if (dma != phys) goto out_unmap; }kmemleak_ignore (table);
Signature · 1 line
2.17.0
PATCH 1/1 iommu/io-pgtable-arm-v7s: Abort allocation when table address overflows the PTE
Quoted 10 lines · Jean-Philippe Brucker
When run on a 64-bit system in selftest, the v7s driver may obtain page table with physical addresses larger than 32-bit. Level-2 tables are 1KB and are are allocated with slab, which doesn't accept the
GFP_DMA32flag. Currentlymap()truncates the address written in the PTE, causingiova_to_phys()orunmap()to access invalid memory. Kasan reports it as a use-after-free. To avoid any nasty surprise, test if the physical address fits in a PTE before returning a new table. 32-bit systems, which are the main users of this page table format, shouldn't see any difference.
Quoted 4 lines
Signed-off-by Jean-Philippe Brucker <[email protected]>--- drivers/iommu/io-pgtable-arm-v7s.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
Thanks, I'll queue this too.
It would be nice if we could use GFP_DMA32 instead of failing the request, but that doesn't work at all with the kmem_cache so we'd have to roll our own l2 allocator if we wanted to support this.
Will