Skip to content

Commit 466556d

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 cab5150 commit 466556d

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, Write};
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
@@ -254,16 +257,40 @@ pub fn create(
254257
let mut builder = MmapRegionBuilder::new_with_bitmap(
255258
size,
256259
track_dirty_pages.then(|| AtomicBitmap::with_len(size)),
257-
)
258-
.with_mmap_prot(libc::PROT_READ | libc::PROT_WRITE)
259-
.with_mmap_flags(libc::MAP_NORESERVE | mmap_flags);
260+
);
260261

261-
if let Some(ref file) = file {
262+
// when computing offset below we ensure it fits into i64
263+
#[allow(clippy::cast_possible_wrap)]
264+
let (fd, fd_off) = if let Some(ref file) = file {
262265
let file_offset = FileOffset::from_arc(Arc::clone(file), offset);
263266

264267
builder = builder.with_file_offset(file_offset);
268+
269+
(file.as_raw_fd(), offset as libc::off_t)
270+
} else {
271+
(-1, 0)
272+
};
273+
274+
// SAFETY: the arguments to mmap cannot cause any memory unsafety in the rust sense
275+
let ptr = unsafe {
276+
libc::mmap(
277+
null_mut(),
278+
size,
279+
libc::PROT_READ | libc::PROT_WRITE,
280+
libc::MAP_NORESERVE | mmap_flags,
281+
fd,
282+
fd_off,
283+
)
284+
};
285+
286+
if ptr == libc::MAP_FAILED {
287+
return Err(MemoryError::Mmap(std::io::Error::last_os_error()));
265288
}
266289

290+
// SAFETY: we check above that mmap succeeded, and the size we passed to builder is the
291+
// same as the size of the mmap area.
292+
let builder = unsafe { builder.with_raw_mmap_pointer(ptr.cast()) };
293+
267294
offset = match offset.checked_add(size as u64) {
268295
None => return Err(MemoryError::OffsetTooLarge),
269296
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)