iommufd builds the reserved IOVA ranges of an IOAS in iopt_table_enforce_dev_resv_regions() by calling the per-device iommu_get_resv_regions(), which only returns IOMMU driver-level reserved regions (RMRR, unity maps, MSI windows, etc.) and does not include PCI host bridge MMIO windows. As a result, the ranges reported to userspace by IOMMU_IOAS_IOVA_RANGES may overlap with a host bridge's MMIO windows, allowing userspace to map IOVAs that a PCIe switch might misinterpret as peer-to-peer DMA and misroute to the wrong device. VFIO type1 avoids this because it collects reserved regions through iommu_get_group_resv_regions(), which already reserves PCI host bridge MMIO windows. Switch iommufd to iommu_get_group_resv_regions() as well so that the IOAS reserved set includes PCI host bridge MMIO windows and IOMMU_IOAS_IOVA_RANGES no longer hands out IOVAs overlapping them, aligning iommufd behaviour with VFIO type1. The per-device @dev is kept as the reservation owner so that per-device detach cleanup via __iopt_remove_reserved_iova() continues to work unchanged. Signed-off-by: Guanghui Feng --- drivers/iommu/iommufd/io_pagetable.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/iommufd/io_pagetable.c b/drivers/iommu/iommufd/io_pagetable.c index 4e447ce74cf6..7198deba378e 100644 --- a/drivers/iommu/iommufd/io_pagetable.c +++ b/drivers/iommu/iommufd/io_pagetable.c @@ -1582,6 +1582,7 @@ int iopt_table_enforce_dev_resv_regions(struct io_pagetable *iopt, phys_addr_t *sw_msi_start) { struct iommu_resv_region *resv; + struct iommu_group *group; LIST_HEAD(resv_regions); unsigned int num_hw_msi = 0; unsigned int num_sw_msi = 0; @@ -1591,8 +1592,16 @@ int iopt_table_enforce_dev_resv_regions(struct io_pagetable *iopt, return -EINVAL; down_write(&iopt->iova_rwsem); - /* FIXME: drivers allocate memory but there is no failure propagated */ - iommu_get_resv_regions(dev, &resv_regions); + + group = iommu_group_get(dev); + if (!group) { + rc = -ENODEV; + goto out_unlock; + } + + rc = iommu_get_group_resv_regions(group, &resv_regions); + if (rc) + goto out_free_resv; list_for_each_entry(resv, &resv_regions, list) { if (resv->type == IOMMU_RESV_DIRECT_RELAXABLE) @@ -1624,6 +1633,8 @@ int iopt_table_enforce_dev_resv_regions(struct io_pagetable *iopt, __iopt_remove_reserved_iova(iopt, dev); out_free_resv: iommu_put_resv_regions(dev, &resv_regions); + iommu_group_put(group); +out_unlock: up_write(&iopt->iova_rwsem); return rc; } -- 2.43.7