iommu: Protect against overflow in iommu_pgsize()
[ Upstream commit e586e22974d2b7acbef3c6c3e01b2d5ce69efe33 ]
On a 32 bit system calling:
iommu_map(0, 0x40000000)
When using the AMD V1 page table type with a domain->pgsize of 0xfffff000
causes iommu_pgsize() to miscalculate a result of:
size=0x40000000 count=2
count should be 1. This completely corrupts the mapping process.
This is because the final test to adjust the pagesize malfunctions when
the addition overflows. Use check_add_overflow() to prevent this.
Fixes: b1d99dc5f9
("iommu: Hook up '->unmap_pages' driver callback")
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Link: https://lore.kernel.org/r/0-v1-3ad28fc2e3a3+163327-iommu_overflow_pgsize_jgg@nvidia.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
cb4b936946
commit
8fa998b842
@@ -2382,6 +2382,7 @@ static size_t iommu_pgsize(struct iommu_domain *domain, unsigned long iova,
|
|||||||
unsigned int pgsize_idx, pgsize_idx_next;
|
unsigned int pgsize_idx, pgsize_idx_next;
|
||||||
unsigned long pgsizes;
|
unsigned long pgsizes;
|
||||||
size_t offset, pgsize, pgsize_next;
|
size_t offset, pgsize, pgsize_next;
|
||||||
|
size_t offset_end;
|
||||||
unsigned long addr_merge = paddr | iova;
|
unsigned long addr_merge = paddr | iova;
|
||||||
|
|
||||||
/* Page sizes supported by the hardware and small enough for @size */
|
/* Page sizes supported by the hardware and small enough for @size */
|
||||||
@@ -2422,7 +2423,8 @@ static size_t iommu_pgsize(struct iommu_domain *domain, unsigned long iova,
|
|||||||
* If size is big enough to accommodate the larger page, reduce
|
* If size is big enough to accommodate the larger page, reduce
|
||||||
* the number of smaller pages.
|
* the number of smaller pages.
|
||||||
*/
|
*/
|
||||||
if (offset + pgsize_next <= size)
|
if (!check_add_overflow(offset, pgsize_next, &offset_end) &&
|
||||||
|
offset_end <= size)
|
||||||
size = offset;
|
size = offset;
|
||||||
|
|
||||||
out_set_count:
|
out_set_count:
|
||||||
|
Reference in New Issue
Block a user