mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
pci: clamp sparse mmap holes to physical BAR
For VFIO devices with non page aligned MSI-X offsets,
fixup_msix_region() relocates MSI-X table and PBA offsets
into an enlarged virtual BAR by mutating msix.cap in place.
generate_sparse_areas() later reads those relocated offsets
to carve mmap holes, but receives the physical BAR size as
region_size. The relocated offsets exceed the physical BAR
boundary, and the kernel rejects the mmap with EINVAL.
Guard inter_ranges insertion with an offset < region_size
check so relocated entries are skipped. The full physical
BAR is mmapped as a single region. The relocated MSI-X in
the upper half of the virtual BAR remains trapped because
it has no mmap backing.
Linux kernel commit a32295c612c5 ("vfio-pci: Allow mapping
MSIX BAR") allows mmapping the entire BAR including the
MSI-X region when VFIO_REGION_INFO_CAP_MSIX_MAPPABLE is
advertised. The actual security guarantees come from IOMMU
isolation and interrupt remapping, not from filtering
MSI-X table accesses. QEMU follows the same pattern,
mmapping the entire physical BAR when MsixMappable is
present.
Fixes: #7898
Signed-off-by: Saravanan D <saravanand@crusoe.ai>
This commit is contained in:
committed by
Rob Bradford
parent
1bc49758a0
commit
9156758828
@@ -1562,13 +1562,33 @@ impl VfioPciDevice {
|
||||
let (offset, size) = msix.cap.table_range();
|
||||
let offset = align_page_size_down(offset);
|
||||
let size = align_page_size_up(size);
|
||||
inter_ranges.insert(offset, size);
|
||||
// MSI-X mmap region safety: when a device has a non page
|
||||
// aligned MSI-X offset, fixup_msix_region() relocates MSI-X
|
||||
// to the upper half of an enlarged virtual BAR, causing the
|
||||
// offsets in msix.cap to exceed the physical BAR size. This
|
||||
// check skips carving a hole, preventing invalid offsets from
|
||||
// reaching the mmap path. With no holes,
|
||||
// generate_sparse_areas() returns a single sparse region
|
||||
// covering the entire physical BAR. The relocated MSI-X in
|
||||
// the virtual BAR remains trapped because its upper half has
|
||||
// no mmap backing. Exposing the physical MSI-X region through
|
||||
// mmap is safe when the kernel advertises
|
||||
// VFIO_REGION_INFO_CAP_MSIX_MAPPABLE. When MSI-X offsets are
|
||||
// already page aligned, fixup_msix_region() does not relocate
|
||||
// and this check is satisfied, so a hole is carved at the
|
||||
// intended offset as before.
|
||||
if offset < region_size {
|
||||
inter_ranges.insert(offset, size);
|
||||
}
|
||||
}
|
||||
if region_index == msix.cap.pba_bir() {
|
||||
let (offset, size) = msix.cap.pba_range();
|
||||
let offset = align_page_size_down(offset);
|
||||
let size = align_page_size_up(size);
|
||||
inter_ranges.insert(offset, size);
|
||||
// See MSI-X mmap safety comment above.
|
||||
if offset < region_size {
|
||||
inter_ranges.insert(offset, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user