Commit e6c47bebdf for qemu.org

commit e6c47bebdf8628e635e1ba970919ca96d572dbbe
Author: Chenyi Qiang <chenyi.qiang@intel.com>
Date:   Wed May 27 18:11:08 2026 +0800

    vfio/container: Restrict dma_map_file() to shared RAM or RAM devices

    vfio_container_dma_map() uses dma_map_file() whenever a RAMBlock has an
    fd and the VFIO IOMMU backend supports file-based DMA mapping. That is
    not correct for private file-backed guest RAM.

    dma_map_file() resolves PFNs from the backing file, but private guest
    RAM mappings (MAP_PRIVATE) can run on different PFNs than the file
    because they are subject to copy-on-write (COW) anomalies. As a result,
    using dma_map_file() on a privately mapped RAMBlock can program DMA
    against pages that do not back QEMU's actual guest memory.

    Fix this by using dma_map_file() only for shared mapped RAMBlocks
    (MAP_SHARED) or RAM device regions.

    Fixes: fb32965b6dd8 ("vfio/iommufd: use IOMMU_IOAS_MAP_FILE")
    Reported-by: Farrah Chen <farrah.chen@intel.com>
    Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220776
    Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
    Suggested-by: Cédric Le Goater <clg@redhat.com>
    Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com>
    Link: https://lore.kernel.org/qemu-devel/20260527101109.71781-1-chenyi.qiang@intel.com
    Reviewed-by: Cédric Le Goater <clg@redhat.com>
    Signed-off-by: Cédric Le Goater <clg@redhat.com>

diff --git a/hw/vfio/container.c b/hw/vfio/container.c
index 4c2816b574..56bd9ac009 100644
--- a/hw/vfio/container.c
+++ b/hw/vfio/container.c
@@ -74,15 +74,43 @@ void vfio_address_space_insert(VFIOAddressSpace *space,
     bcontainer->space = space;
 }

+static bool vfio_container_can_dma_map_file(VFIOContainer *bcontainer,
+                                            MemoryRegion *mr, int *fd)
+{
+    VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
+    RAMBlock *rb = mr->ram_block;
+
+    if (!vioc->dma_map_file || !rb) {
+        return false;
+    }
+
+    *fd = qemu_ram_get_fd(rb);
+    if (*fd < 0) {
+        return false;
+    }
+
+    /*
+     * We can use IOMMU DMA mapping (IOMMU_IOAS_MAP_FILE) for :
+     *
+     * 1) Guest RAM blocks explicitly configured as shared (MAP_SHARED)
+     * 2) RAM device sub-regions (MMIO BARs)
+     *
+     * Private RAM mappings (MAP_PRIVATE) are strictly excluded. Because
+     * they are subject to copy-on-write (COW) anomalies, their underlying
+     * PFNs can permanently diverge from the backing file
+     */
+    return qemu_ram_is_shared(rb) || memory_region_is_ram_device(mr);
+}
+
 int vfio_container_dma_map(VFIOContainer *bcontainer,
                            hwaddr iova, uint64_t size,
                            void *vaddr, bool readonly, MemoryRegion *mr)
 {
     VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
-    RAMBlock *rb = mr->ram_block;
-    int mfd = rb ? qemu_ram_get_fd(rb) : -1;
+    int mfd;

-    if (mfd >= 0 && vioc->dma_map_file) {
+    if (vfio_container_can_dma_map_file(bcontainer, mr, &mfd)) {
+        RAMBlock *rb = mr->ram_block;
         unsigned long start = vaddr - qemu_ram_get_host_addr(rb);
         unsigned long offset = qemu_ram_get_fd_offset(rb);