Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iommu/dma: Fix iova map result check bug

The data type of the return value of the iommu_map_sg_atomic
is ssize_t, but the data type of iova size is size_t,
e.g. one is int while the other is unsigned int.

When iommu_map_sg_atomic return value is compared with iova size,
it will force the signed int to be converted to unsigned int, if
iova map fails and iommu_map_sg_atomic return error code is less
than 0, then (ret < iova_len) is false, which will to cause not
do free iova, and the master can still successfully get the iova
of map fail, which is not expected.

Therefore, we need to check the return value of iommu_map_sg_atomic
in two cases according to whether it is less than 0.

Fixes: ad8f36e4b6b1 ("iommu: return full error code from iommu_map_sg[_atomic]()")
Signed-off-by: Yunfei Wang <yf.wang@mediatek.com>
Cc: <stable@vger.kernel.org> # 5.15.*
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Reviewed-by: Miles Chen <miles.chen@mediatek.com>
Link: https://lore.kernel.org/r/20220507085204.16914-1-yf.wang@mediatek.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>

authored by

Yunfei Wang and committed by
Joerg Roedel
a3884774 e8ae0e14

+4 -3
+4 -3
drivers/iommu/dma-iommu.c
··· 776 776 unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap; 777 777 struct page **pages; 778 778 dma_addr_t iova; 779 + ssize_t ret; 779 780 780 781 if (static_branch_unlikely(&iommu_deferred_attach_enabled) && 781 782 iommu_deferred_attach(dev, domain)) ··· 814 813 arch_dma_prep_coherent(sg_page(sg), sg->length); 815 814 } 816 815 817 - if (iommu_map_sg_atomic(domain, iova, sgt->sgl, sgt->orig_nents, ioprot) 818 - < size) 816 + ret = iommu_map_sg_atomic(domain, iova, sgt->sgl, sgt->orig_nents, ioprot); 817 + if (ret < 0 || ret < size) 819 818 goto out_free_sg; 820 819 821 820 sgt->sgl->dma_address = iova; ··· 1215 1214 * implementation - it knows better than we do. 1216 1215 */ 1217 1216 ret = iommu_map_sg_atomic(domain, iova, sg, nents, prot); 1218 - if (ret < iova_len) 1217 + if (ret < 0 || ret < iova_len) 1219 1218 goto out_free_iova; 1220 1219 1221 1220 return __finalise_sg(dev, sg, nents, iova);