mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
pci: vfio_user: bounds-check size in DMA map
VfioUserDmaMapping::map is reached from the virtio-iommu MAP handler with (iova, gpa, size) all guest-controlled. Validate the length of the region fits, not just the start. Before this change the vfio-user on the other end could get a size that spans past the end of its backing storage. Signed-off-by: Dylan Reid <dgreid@fb.com>
This commit is contained in:
+26
-15
@@ -557,23 +557,34 @@ impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMappi
|
|||||||
fn map(&self, iova: u64, gpa: u64, size: u64) -> std::result::Result<(), std::io::Error> {
|
fn map(&self, iova: u64, gpa: u64, size: u64) -> std::result::Result<(), std::io::Error> {
|
||||||
let mem = self.memory.memory();
|
let mem = self.memory.memory();
|
||||||
let guest_addr = GuestAddress(gpa);
|
let guest_addr = GuestAddress(gpa);
|
||||||
let region = mem.find_region(guest_addr);
|
let Some(region) = mem.find_region(guest_addr) else {
|
||||||
|
return Err(std::io::Error::other(format!(
|
||||||
if let Some(region) = region {
|
|
||||||
let file_offset = region.file_offset().unwrap();
|
|
||||||
let offset = (GuestAddress(gpa).checked_offset_from(region.start_addr())).unwrap()
|
|
||||||
+ file_offset.start();
|
|
||||||
|
|
||||||
self.client
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.dma_map(offset, iova, size, file_offset.file().as_raw_fd())
|
|
||||||
.map_err(|e| std::io::Error::other(format!("Error mapping region: {e}")))
|
|
||||||
} else {
|
|
||||||
Err(std::io::Error::other(format!(
|
|
||||||
"Region not found for 0x{gpa:x}"
|
"Region not found for 0x{gpa:x}"
|
||||||
)))
|
)));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check that the range fits in the region.
|
||||||
|
let region_offset = guest_addr
|
||||||
|
.checked_offset_from(region.start_addr())
|
||||||
|
.ok_or_else(|| std::io::Error::other(format!("gpa 0x{gpa:x} below region start")))?;
|
||||||
|
let region_remaining = (region.len())
|
||||||
|
.checked_sub(region_offset)
|
||||||
|
.ok_or_else(|| std::io::Error::other(format!("gpa 0x{gpa:x} past region end")))?;
|
||||||
|
if size > region_remaining {
|
||||||
|
return Err(std::io::Error::other(format!(
|
||||||
|
"DMA map (gpa 0x{gpa:x}, size 0x{size:x}) extends past region end"
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unwrap is safe as we only do vfio with shared mem with a backing file.
|
||||||
|
let file_offset = region.file_offset().unwrap();
|
||||||
|
let offset = region_offset + file_offset.start();
|
||||||
|
|
||||||
|
self.client
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.dma_map(offset, iova, size, file_offset.file().as_raw_fd())
|
||||||
|
.map_err(|e| std::io::Error::other(format!("Error mapping region: {e}")))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unmap(&self, iova: u64, size: u64) -> std::result::Result<(), std::io::Error> {
|
fn unmap(&self, iova: u64, size: u64) -> std::result::Result<(), std::io::Error> {
|
||||||
|
|||||||
Reference in New Issue
Block a user