misc: Mark memory region APIs as unsafe

To ensure that struct sizes are the same on 32-bit and 64-bit, various
kernel APIs use __u64 (Rust u64) to represent userspace pointers.
Userspace is expected to cast pointers to __u64 before passing them to
the kernel, and cast kernel-provided __u64 to a pointer before using
them.  However, various safe APIs in Cloud Hypervisor took
caller-provided u64 values and passed them to syscalls that treat them
as userspace addresses.  Therefore, passing bad u64 values would cause
memory disclosure or corruption.  The memory region APIs are one example
of this, so mark them as unsafe.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
This commit is contained in:
Demi Marie Obenour 2025-06-13 14:27:00 -04:00 committed by Rob Bradford
parent 00f0b9e42c
commit fdc19ad85e
12 changed files with 489 additions and 407 deletions

View file

@ -1663,21 +1663,22 @@ impl VfioPciDevice {
host_addr: host_addr as u64,
};
// SAFETY: host_addr was allocated by mmap() and points to size
// bytes of memory.
unsafe {
self.vm.create_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
)
}
.map_err(VfioPciError::CreateUserMemoryRegion)?;
region.user_memory_regions.push(user_memory_region);
let mem_region = self.vm.make_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
);
self.vm
.create_user_memory_region(mem_region)
.map_err(VfioPciError::CreateUserMemoryRegion)?;
if !self.iommu_attached {
self.container
.vfio_dma_map(
@ -1714,16 +1715,18 @@ impl VfioPciDevice {
}
// Remove region
let r = self.vm.make_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
);
if let Err(e) = self.vm.remove_user_memory_region(r) {
// SAFETY: only valid entries are added to the user_memory_regions field
// of the entries of self.common.mmio_regions.
if let Err(e) = unsafe {
self.vm.remove_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
)
} {
error!("Could not remove the userspace memory region: {e}");
}
@ -1898,20 +1901,19 @@ impl PciDevice for VfioPciDevice {
user_memory_region.start, user_memory_region.size, e
);
}
// Remove old region
let old_mem_region = self.vm.make_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
);
self.vm
.remove_user_memory_region(old_mem_region)
.map_err(io::Error::other)?;
// SAFETY: user_memory_regions has valid entries
unsafe {
self.vm.remove_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
)
}
.map_err(io::Error::other)?;
// Update the user memory region with the correct start address.
if new_base > old_base {
@ -1921,18 +1923,18 @@ impl PciDevice for VfioPciDevice {
}
// Insert new region
let new_mem_region = self.vm.make_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
);
self.vm
.create_user_memory_region(new_mem_region)
.map_err(io::Error::other)?;
// SAFETY: mmio_regions only has valid values
unsafe {
self.vm.create_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
)
}
.map_err(io::Error::other)?;
// Map the moved mmio region to vfio container
if !self.iommu_attached {

View file

@ -110,7 +110,10 @@ impl VfioUserPciDevice {
})
}
pub fn map_mmio_regions(&mut self) -> Result<(), VfioUserPciDeviceError> {
/// # Safety
///
/// Not known yet (TODO)
pub unsafe fn map_mmio_regions(&mut self) -> Result<(), VfioUserPciDeviceError> {
for mmio_region in &mut self.common.mmio_regions {
let region_flags = self
.client
@ -184,20 +187,21 @@ impl VfioUserPciDevice {
host_addr: host_addr as u64,
};
// SAFETY: host_addr was just allocated with mmap()
// and points to size bytes of valid address.
unsafe {
self.vm.create_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
)
}
.map_err(VfioUserPciDeviceError::MapRegionGuest)?;
mmio_region.user_memory_regions.push(user_memory_region);
let mem_region = self.vm.make_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
);
self.vm
.create_user_memory_region(mem_region)
.map_err(VfioUserPciDeviceError::MapRegionGuest)?;
}
}
}
@ -209,16 +213,17 @@ impl VfioUserPciDevice {
for mmio_region in self.common.mmio_regions.iter() {
for user_memory_region in mmio_region.user_memory_regions.iter() {
// Remove region
let r = self.vm.make_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
);
if let Err(e) = self.vm.remove_user_memory_region(r) {
// SAFETY: only valid regions are in user_memory_regions
if let Err(e) = unsafe {
self.vm.remove_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
)
} {
error!("Could not remove the userspace memory region: {e}");
}
@ -455,18 +460,18 @@ impl PciDevice for VfioUserPciDevice {
for user_memory_region in mmio_region.user_memory_regions.iter_mut() {
// Remove old region
let old_region = self.vm.make_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
);
self.vm
.remove_user_memory_region(old_region)
.map_err(std::io::Error::other)?;
// SAFETY: only valid regions are in user_memory_regions
unsafe {
self.vm.remove_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
)
}
.map_err(std::io::Error::other)?;
// Update the user memory region with the correct start address.
if new_base > old_base {
@ -476,18 +481,18 @@ impl PciDevice for VfioUserPciDevice {
}
// Insert new region
let new_region = self.vm.make_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
);
self.vm
.create_user_memory_region(new_region)
.map_err(std::io::Error::other)?;
// SAFETY: only valid regions are in user_memory_regions
unsafe {
self.vm.create_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
)
}
.map_err(std::io::Error::other)?;
}
info!("Moved bar 0x{old_base:x} -> 0x{new_base:x}");
}