From 5b199498ffbaa718a6007654e69859787a5a4862 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Fri, 24 Apr 2026 16:56:59 -0700 Subject: [PATCH] virtio-devices: iommu: checked arithmetic for MAP Catch u64 overflows on map so that later translation requests from the guest don't have a vector for causing a host panic. Signed-off-by: Dylan Reid --- virtio-devices/src/iommu.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/virtio-devices/src/iommu.rs b/virtio-devices/src/iommu.rs index bc03e6775..c99de399a 100644 --- a/virtio-devices/src/iommu.rs +++ b/virtio-devices/src/iommu.rs @@ -494,12 +494,25 @@ impl Request { .map(|(&e, _)| e) .collect(); + let Some(size) = req + .virt_end + .checked_sub(req.virt_start) + .and_then(|delta| delta.checked_add(1)) + else { + status = VIRTIO_IOMMU_S_RANGE; + return Err(Error::InvalidMapRequest); + }; + + if req.phys_start > u64::MAX - size || req.virt_start > u64::MAX - size { + status = VIRTIO_IOMMU_S_RANGE; + return Err(Error::InvalidMapRequest); + } + // For viommu all endpoints receive their own VFIO container, as a result // Each endpoint within the domain needs to be separately mapped, as the // mapping is done on a per-container level, not a per-domain level for endpoint in endpoints { if let Some(ext_map) = ext_mapping.get(&endpoint) { - let size = req.virt_end - req.virt_start + 1; ext_map .map(req.virt_start, req.phys_start, size) .map_err(Error::ExternalMapping)?; @@ -518,7 +531,7 @@ impl Request { req.virt_start, Mapping { gpa: req.phys_start, - size: req.virt_end - req.virt_start + 1, + size, }, ); } @@ -558,10 +571,18 @@ impl Request { .map(|(&e, _)| e) .collect(); + let Some(size) = req + .virt_end + .checked_sub(virt_start) + .and_then(|d| d.checked_add(1)) + else { + status = VIRTIO_IOMMU_S_RANGE; + return Err(Error::InvalidUnmapRequest); + }; + // Trigger external unmapping if necessary. for endpoint in endpoints { if let Some(ext_map) = ext_mapping.get(&endpoint) { - let size = req.virt_end - virt_start + 1; ext_map .unmap(virt_start, size) .map_err(Error::ExternalUnmapping)?;