Skip to content

Commit b398d53

Browse files
committed
Add Copy on Write support on the host for nanvix
Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
1 parent 3517c0c commit b398d53

File tree

1 file changed

+36
-11
lines changed

1 file changed

+36
-11
lines changed

src/hyperlight_host/src/sandbox/file_mapping.rs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ use crate::mem::memory_region::{HostRegionBase, MemoryRegionKind};
4141
use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags, MemoryRegionType};
4242
use crate::{Result, log_then_return};
4343

44+
/// Returns the guest-side permission flags for file mappings.
45+
///
46+
/// With the `nanvix-unstable` feature, files are mapped as
47+
/// `READ | WRITE | EXECUTE` (copy-on-write). Otherwise the default
48+
/// is `READ | EXECUTE` (read-only + executable).
49+
fn file_mapping_flags() -> MemoryRegionFlags {
50+
#[cfg(feature = "nanvix-unstable")]
51+
{
52+
MemoryRegionFlags::READ | MemoryRegionFlags::WRITE | MemoryRegionFlags::EXECUTE
53+
}
54+
#[cfg(not(feature = "nanvix-unstable"))]
55+
{
56+
MemoryRegionFlags::READ | MemoryRegionFlags::EXECUTE
57+
}
58+
}
59+
4460
/// A prepared (host-side) file mapping ready to be applied to a VM.
4561
///
4662
/// Created by [`prepare_file_cow`]. The host-side OS resources (file
@@ -166,7 +182,7 @@ impl PreparedFileMapping {
166182
Ok(MemoryRegion {
167183
host_region: host_base..host_end,
168184
guest_region: guest_start..guest_end,
169-
flags: MemoryRegionFlags::READ | MemoryRegionFlags::EXECUTE,
185+
flags: file_mapping_flags(),
170186
region_type: MemoryRegionType::MappedFile,
171187
})
172188
}
@@ -186,7 +202,7 @@ impl PreparedFileMapping {
186202
host_region: *mmap_base as usize
187203
..(*mmap_base as usize).wrapping_add(*mmap_size),
188204
guest_region: guest_start..guest_end,
189-
flags: MemoryRegionFlags::READ | MemoryRegionFlags::EXECUTE,
205+
flags: file_mapping_flags(),
190206
region_type: MemoryRegionType::MappedFile,
191207
})
192208
}
@@ -295,7 +311,8 @@ pub(crate) fn prepare_file_cow(
295311

296312
use windows::Win32::Foundation::HANDLE;
297313
use windows::Win32::System::Memory::{
298-
CreateFileMappingW, FILE_MAP_READ, MapViewOfFile, PAGE_READONLY,
314+
CreateFileMappingW, FILE_MAP_COPY, FILE_MAP_READ, MapViewOfFile, PAGE_READONLY,
315+
PAGE_WRITECOPY,
299316
};
300317

301318
let file = std::fs::File::options().read(true).open(file_path)?;
@@ -312,18 +329,23 @@ pub(crate) fn prepare_file_cow(
312329

313330
let file_handle = HANDLE(file.as_raw_handle());
314331

315-
// Create a read-only file mapping object backed by the actual file.
332+
// nanvix-unstable maps files as RWX (CoW), so use
333+
// PAGE_WRITECOPY / FILE_MAP_COPY; otherwise PAGE_READONLY
334+
#[cfg(feature = "nanvix-unstable")]
335+
let (page_prot, map_access) = (PAGE_WRITECOPY, FILE_MAP_COPY);
336+
#[cfg(not(feature = "nanvix-unstable"))]
337+
let (page_prot, map_access) = (PAGE_READONLY, FILE_MAP_READ);
338+
316339
// Pass 0,0 for size to use the file's actual size — Windows will
317340
// NOT extend a read-only file, so requesting page-aligned size
318341
// would fail for files smaller than one page.
319342
let mapping_handle =
320-
unsafe { CreateFileMappingW(file_handle, None, PAGE_READONLY, 0, 0, None) }
343+
unsafe { CreateFileMappingW(file_handle, None, page_prot, 0, 0, None) }
321344
.map_err(|e| HyperlightError::Error(format!("CreateFileMappingW failed: {e}")))?;
322345

323-
// Map a read-only view into the host process.
324346
// Passing 0 for dwNumberOfBytesToMap maps the entire file; the OS
325347
// rounds up to the next page boundary and zero-fills the remainder.
326-
let view = unsafe { MapViewOfFile(mapping_handle, FILE_MAP_READ, 0, 0, 0) };
348+
let view = unsafe { MapViewOfFile(mapping_handle, map_access, 0, 0, 0) };
327349
if view.Value.is_null() {
328350
unsafe {
329351
let _ = windows::Win32::Foundation::CloseHandle(mapping_handle);
@@ -363,12 +385,15 @@ pub(crate) fn prepare_file_cow(
363385
// MSHV's map_user_memory requires host-writable pages (the
364386
// kernel module calls get_user_pages with write access).
365387
// KVM's KVM_MEM_READONLY slots work with read-only host pages.
388+
// nanvix-unstable needs PROT_WRITE for CoW guest mappings.
366389
// PROT_EXEC is never needed — the hypervisor backs guest R+X
367390
// pages without requiring host-side execute permission.
368-
#[cfg(mshv3)]
369-
let prot = libc::PROT_READ | libc::PROT_WRITE;
370-
#[cfg(not(mshv3))]
371-
let prot = libc::PROT_READ;
391+
let needs_write = cfg!(mshv3) || cfg!(feature = "nanvix-unstable");
392+
let prot = if needs_write {
393+
libc::PROT_READ | libc::PROT_WRITE
394+
} else {
395+
libc::PROT_READ
396+
};
372397

373398
libc::mmap(
374399
std::ptr::null_mut(),

0 commit comments

Comments
 (0)