@samitouri / QOSamiQemu / commits / e6c47bebdf

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>

Chenyi Qiang committed May 27, 2026 at 18:11 UTC e6c47bebdf8628e635e1ba970919ca96d572dbbe
1 file changed +31 -3
hw/vfio/container.c
+31 -3
@@ -74,15 +74,43 @@ void vfio_address_space_insert(VFIOAddressSpace *space,
74 bcontainer->space = space;
75 }
76
77 +static bool vfio_container_can_dma_map_file(VFIOContainer *bcontainer,
78 + MemoryRegion *mr, int *fd)
79 +{
80 + VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
81 + RAMBlock *rb = mr->ram_block;
82 +
83 + if (!vioc->dma_map_file || !rb) {
84 + return false;
85 + }
86 +
87 + *fd = qemu_ram_get_fd(rb);
88 + if (*fd < 0) {
89 + return false;
90 + }
91 +
92 + /*
93 + * We can use IOMMU DMA mapping (IOMMU_IOAS_MAP_FILE) for :
94 + *
95 + * 1) Guest RAM blocks explicitly configured as shared (MAP_SHARED)
96 + * 2) RAM device sub-regions (MMIO BARs)
97 + *
98 + * Private RAM mappings (MAP_PRIVATE) are strictly excluded. Because
99 + * they are subject to copy-on-write (COW) anomalies, their underlying
100 + * PFNs can permanently diverge from the backing file
101 + */
102 + return qemu_ram_is_shared(rb) || memory_region_is_ram_device(mr);
103 +}
104 +
105 int vfio_container_dma_map(VFIOContainer *bcontainer,
106 hwaddr iova, uint64_t size,
107 void *vaddr, bool readonly, MemoryRegion *mr)
108 {
109 VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
82 - RAMBlock *rb = mr->ram_block;
83 - int mfd = rb ? qemu_ram_get_fd(rb) : -1;
110 + int mfd;
111
85 - if (mfd >= 0 && vioc->dma_map_file) {
112 + if (vfio_container_can_dma_map_file(bcontainer, mr, &mfd)) {
113 + RAMBlock *rb = mr->ram_block;
114 unsigned long start = vaddr - qemu_ram_get_host_addr(rb);
115 unsigned long offset = qemu_ram_get_fd_offset(rb);
116