It is possible, when a very large mapping uses a single scatterlist, that padding overflows scatterlist's length field. This results in: 1) silently wrapping the value 2) smaller than desired mappings produced by iommu_map_sg 3) leaving mapped bytes in memory (no iommu_unmap)
Address this issue by adding overflow detection for previous scatterlist length field. Signed-off-by: Krzysztof Karas <[email protected]> --- v2: * Address overflows instead of unmapping erroneously mapped memory (Robin). * Put this patch last for easier reproduction of the issue. drivers/iommu/dma-iommu.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 9abaec0703ef..c403057577df 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -1493,8 +1493,18 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, * time through here (i.e. before it has a meaningful value). */ if (pad_len && pad_len < s_length - 1) { - prev->length += pad_len; - iova_len += pad_len; + if (overflows_type(prev->length + pad_len, prev->length)) { + /* + * For large mappings spanning multiple GBs we + * may not be able to fit all needed padding into + * sg->length. + */ + ret = -EOVERFLOW; + goto out_restore_sg; + } else { + prev->length += pad_len; + iova_len += pad_len; + } } iova_len += s_length; -- 2.34.1
