mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
misc: Work around vfio_dma_map being unsound
This API passes a u64 to a kernel API that treats the u64 as a userspace address. Therefore, it should be marked unsafe, but it currently is not [1]. Wrap the call in an unsafe block to document that invariants must be upheld to avoid undefined behavior. This causes a compiler warning, so suppress the warning with #[allow(unused_unsafe)]. [1]: https://github.com/rust-vmm/vfio/issues/100 Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
This commit is contained in:
committed by
Rob Bradford
parent
12c7cc5e4f
commit
8be28f8438
@@ -399,7 +399,7 @@ impl BlocksState {
|
||||
|
||||
struct MemEpollHandler {
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
host_addr: u64,
|
||||
region: Arc<GuestRegionMmap>,
|
||||
host_fd: Option<RawFd>,
|
||||
blocks_state: Arc<Mutex<BlocksState>>,
|
||||
config: Arc<Mutex<VirtioMemConfig>>,
|
||||
@@ -412,8 +412,45 @@ struct MemEpollHandler {
|
||||
dma_mapping_handlers: Arc<Mutex<BTreeMap<VirtioMemMappingSource, Arc<dyn ExternalDmaMapping>>>>,
|
||||
}
|
||||
|
||||
fn usize_to_u64(i: usize) -> u64 {
|
||||
const _: () = assert!(size_of::<usize>() <= size_of::<u64>());
|
||||
i as _
|
||||
}
|
||||
|
||||
impl MemEpollHandler {
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if any of the following hold:
|
||||
/// - region size exceeds [`libc::off64_t::MAX`], [`libc::size_t::MAX`],
|
||||
/// or [`isize::MAX`]
|
||||
/// - `size + offset` exceeds the size of the region (including overflow).
|
||||
fn discard_memory_range(&self, offset: u64, size: u64) -> Result<(), Error> {
|
||||
let max_size = usize_to_u64(self.region.size());
|
||||
|
||||
// Validate the region size to ensure the below casts
|
||||
// are lossless.
|
||||
libc::size_t::try_from(max_size).unwrap();
|
||||
libc::off64_t::try_from(max_size).unwrap();
|
||||
isize::try_from(max_size).unwrap();
|
||||
|
||||
// Check that offset is in bounds.
|
||||
assert!(max_size >= offset);
|
||||
|
||||
if size == 0 {
|
||||
// Do not try to deallocate a zero size.
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Check that offset + size is in bounds and does not overflow.
|
||||
// Since size is checked to be nonzero above, this also means that
|
||||
// offset is not past the end.
|
||||
assert!(max_size - offset >= size);
|
||||
|
||||
// Since offset and size are each bounded above by max_size,
|
||||
// and max_size came from usize and was checked to be able to be
|
||||
// losslessly cast to size_t and off64_t, this also checks that offset
|
||||
// and size can each be losslessly cast to all of these types.
|
||||
|
||||
// Use fallocate if the memory region is backed by a file.
|
||||
if let Some(fd) = self.host_fd {
|
||||
// SAFETY: FFI call with valid arguments
|
||||
@@ -435,10 +472,13 @@ impl MemEpollHandler {
|
||||
// Only use madvise if the memory region is not allocated with
|
||||
// hugepages.
|
||||
if !self.hugepages {
|
||||
// SAFETY: FFI call with valid arguments
|
||||
// SAFETY: FFI call with valid arguments.
|
||||
// offset + madvize_size was checked in bounds above,
|
||||
// and madvise_size is checked to not be zero so ptr_offset
|
||||
// alone is not past the end.
|
||||
let res = unsafe {
|
||||
libc::madvise(
|
||||
(self.host_addr + offset) as *mut libc::c_void,
|
||||
self.region.as_ptr().offset(offset as isize) as *mut libc::c_void,
|
||||
size as libc::size_t,
|
||||
libc::MADV_DONTNEED,
|
||||
)
|
||||
@@ -687,7 +727,7 @@ pub struct MemState {
|
||||
pub struct Mem {
|
||||
common: VirtioCommon,
|
||||
id: String,
|
||||
host_addr: u64,
|
||||
region: Arc<GuestRegionMmap>,
|
||||
host_fd: Option<RawFd>,
|
||||
config: Arc<Mutex<VirtioMemConfig>>,
|
||||
seccomp_action: SeccompAction,
|
||||
@@ -780,7 +820,7 @@ impl Mem {
|
||||
..Default::default()
|
||||
},
|
||||
id,
|
||||
host_addr: region.as_ptr() as u64,
|
||||
region: region.clone(),
|
||||
host_fd,
|
||||
config: Arc::new(Mutex::new(config)),
|
||||
seccomp_action,
|
||||
@@ -923,7 +963,7 @@ impl VirtioDevice for Mem {
|
||||
|
||||
let mut handler = MemEpollHandler {
|
||||
mem,
|
||||
host_addr: self.host_addr,
|
||||
region: self.region.clone(),
|
||||
host_fd: self.host_fd,
|
||||
blocks_state: Arc::clone(&self.blocks_state),
|
||||
config: self.config.clone(),
|
||||
|
||||
Reference in New Issue
Block a user