vfio_find_dma_first_node is called to find the first dma node to unmap given an unmap range of [iova..iova+size). The check at the end of the function intends to test if the dma result lies beyond the end of the unmap range. The condition is incorrectly satisfied when iova+size overflows to zero, causing the function to return NULL. The same issue happens inside vfio_dma_do_unmap's while loop. Fix by comparing to the inclusive range end, which can be expressed by u64. This bug was discovered after querying for vfio_iova_range's via VFIO_IOMMU_GET_INFO, making a VFIO_IOMMU_MAP_DMA inside the last range, and then attempting to unmap the entirety of the last range i.e. VFIO_IOMMU_UNMAP_DMA(iova=r.start, size=r.end-r.start+1). --- I don't think iommufd is susceptible to the same issue since iopt_unmap_iova computes the inclusive end using checked addition, and iopt_unmap_iova_range acts on an inclusive range. Signed-off-by: Alex Mastro --- drivers/vfio/vfio_iommu_type1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index f8d68fe77b41..08242d8ce2ca 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -199,7 +199,7 @@ static struct rb_node *vfio_find_dma_first_node(struct vfio_iommu *iommu, node = node->rb_right; } } - if (res && size && dma_res->iova >= start + size) + if (res && size && dma_res->iova > start + size - 1) res = NULL; return res; } @@ -1386,7 +1386,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu, while (n) { dma = rb_entry(n, struct vfio_dma, node); - if (dma->iova >= iova + size) + if (dma->iova > iova + size - 1) break; if (!iommu->v2 && iova > dma->iova) --- base-commit: 407aa63018d15c35a34938633868e61174d2ef6e change-id: 20251005-fix-unmap-c3f3e87dabfa Best regards, -- Alex Mastro