Skip to content

Commit 75f0db6

Browse files
committed
tmp: call mmap outselves
vm-memory has faulty validation logic that prevents us from mmap-ing guest_memfds, so just bypass that by calling mmap ourselves for the time being. See also rust-vmm/vm-memory#320 Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
1 parent 565d5b9 commit 75f0db6

File tree

2 files changed

+32
-7
lines changed

2 files changed

+32
-7
lines changed

src/vmm/src/vstate/memory.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::fs::File;
99
use std::io::{Read, Seek, SeekFrom};
1010
use std::mem::ManuallyDrop;
1111
use std::os::fd::{AsFd, AsRawFd};
12+
use std::ptr::null_mut;
1213
use std::sync::Arc;
1314

1415
use kvm_bindings::{KVM_MEM_LOG_DIRTY_PAGES, kvm_userspace_memory_region2};
@@ -55,6 +56,8 @@ pub enum MemoryError {
5556
MemfdSetLen(std::io::Error),
5657
/// Total sum of memory regions exceeds largest possible file offset
5758
OffsetTooLarge,
59+
/// Error calling mmap: {0}
60+
Mmap(std::io::Error),
5861
}
5962

6063
/// Newtype that implements [`ReadVolatile`] and [`WriteVolatile`] if `T` implements `Read` or
@@ -237,16 +240,40 @@ pub fn create(
237240
let mut builder = MmapRegionBuilder::new_with_bitmap(
238241
size,
239242
track_dirty_pages.then(|| AtomicBitmap::with_len(size)),
240-
)
241-
.with_mmap_prot(libc::PROT_READ | libc::PROT_WRITE)
242-
.with_mmap_flags(libc::MAP_NORESERVE | mmap_flags);
243+
);
243244

244-
if let Some(ref file) = file {
245+
// when computing offset below we ensure it fits into i64
246+
#[allow(clippy::cast_possible_wrap)]
247+
let (fd, fd_off) = if let Some(ref file) = file {
245248
let file_offset = FileOffset::from_arc(Arc::clone(file), offset);
246249

247250
builder = builder.with_file_offset(file_offset);
251+
252+
(file.as_raw_fd(), offset as libc::off_t)
253+
} else {
254+
(-1, 0)
255+
};
256+
257+
// SAFETY: the arguments to mmap cannot cause any memory unsafety in the rust sense
258+
let ptr = unsafe {
259+
libc::mmap(
260+
null_mut(),
261+
size,
262+
libc::PROT_READ | libc::PROT_WRITE,
263+
libc::MAP_NORESERVE | mmap_flags,
264+
fd,
265+
fd_off,
266+
)
267+
};
268+
269+
if ptr == libc::MAP_FAILED {
270+
return Err(MemoryError::Mmap(std::io::Error::last_os_error()));
248271
}
249272

273+
// SAFETY: we check above that mmap succeeded, and the size we passed to builder is the
274+
// same as the size of the mmap area.
275+
let builder = unsafe { builder.with_raw_mmap_pointer(ptr.cast()) };
276+
250277
offset = match offset.checked_add(size as u64) {
251278
None => return Err(MemoryError::OffsetTooLarge),
252279
Some(new_off) if new_off >= i64::MAX as u64 => {

tests/integration_tests/functional/test_api.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,9 +374,7 @@ def test_api_machine_config(uvm_plain):
374374
bad_size = (1 << 64) - 1
375375
test_microvm.api.machine_config.patch(mem_size_mib=bad_size)
376376

377-
fail_msg = re.escape(
378-
"Invalid Memory Configuration: Cannot create mmap region: Out of memory (os error 12)"
379-
)
377+
fail_msg = re.escape("Out of memory (os error 12)")
380378
with pytest.raises(RuntimeError, match=fail_msg):
381379
test_microvm.start()
382380

0 commit comments

Comments
 (0)