Skip to content

Commit 284e620

Browse files
committed
feat: handle hermit images + config nested in image
- fix(isolation): Fix resolution of archive root Without this fix, one gets the following error message: [WARN uhyvelib::isolation::filemap] In hermit image [REDACTED].hermit: unable to find file "." -> /root - Use experimental hermit-entry with image-reader PR applied
1 parent d74257a commit 284e620

File tree

14 files changed

+556
-139
lines changed

14 files changed

+556
-139
lines changed

Cargo.lock

Lines changed: 64 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[workspace]
2+
members = ["uhyve-interface"]
23
exclude = ["tests/test-kernels", "hermit-rs", "hermit-rs/*", "kernel"]
34

45
[package]
@@ -50,7 +51,6 @@ core_affinity = "0.8"
5051
env_logger = "0.11"
5152
gdbstub = "0.7"
5253
gdbstub_arch = "0.3"
53-
hermit-entry = { version = "0.10.5", features = ["loader"] }
5454
libc = "0.2"
5555
log = "0.4"
5656
mac_address = "1.1"
@@ -74,6 +74,12 @@ merge = { version = "0.2" }
7474
yoke = "0.8"
7575
nohash = "0.2"
7676

77+
[dependencies.hermit-entry]
78+
version = "0.10.5"
79+
git = "https://github.com/fogti/hermit-entry"
80+
branch = "image-reader"
81+
features = ["loader", "std"]
82+
7783
[target.'cfg(target_os = "linux")'.dependencies]
7884
kvm-bindings = "0.14"
7985
kvm-ioctls = "0.24"

src/bin/uhyve.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::{fs, num::ParseIntError, path::PathBuf, process, str::FromStr};
55
use clap::{Command, CommandFactory, Parser, error::ErrorKind};
66
use core_affinity::CoreId;
77
use env_logger::Builder;
8-
use log::{LevelFilter, info};
8+
use log::{LevelFilter, info, warn};
99
use merge::Merge;
1010
use serde::Deserialize;
1111
use thiserror::Error;
@@ -346,7 +346,7 @@ impl<'de> serde::de::Deserialize<'de> for Affinity {
346346
#[derive(Debug, Default, Deserialize, Merge, Parser)]
347347
#[cfg_attr(test, derive(PartialEq))]
348348
struct GuestArgs {
349-
/// The kernel to execute
349+
/// The kernel or image to execute
350350
#[clap(value_parser)]
351351
#[serde(skip)]
352352
#[merge(skip)]
@@ -493,14 +493,14 @@ fn run_uhyve() -> i32 {
493493

494494
load_vm_config(&mut args);
495495

496-
let stats = args.uhyve.stats.unwrap_or_default();
497496
let kernel_path = args.guest.kernel.clone();
497+
let stats = args.uhyve.stats.unwrap_or_default();
498498
let affinity = args.cpu.clone().get_affinity(&mut app);
499499
let params = Params::from(args);
500500

501501
let vm = UhyveVm::new(kernel_path, params).unwrap_or_else(|e| panic!("Error: {e}"));
502-
503502
let res = vm.run(affinity);
503+
504504
if stats && let Some(stats) = res.stats {
505505
println!("Run statistics:");
506506
println!("{stats}");
@@ -514,7 +514,7 @@ fn main() {
514514

515515
#[cfg(test)]
516516
mod tests {
517-
use std::env;
517+
use std::{env, path::Path};
518518

519519
use tempfile::tempdir;
520520

@@ -605,9 +605,9 @@ mod tests {
605605
)
606606
.unwrap();
607607

608-
assert!(&config.uhyve.file_mapping.is_empty());
609-
assert!(&config.uhyve.config.is_none());
610-
assert!(&config.guest.kernel.to_str().unwrap().is_empty())
608+
assert!(config.uhyve.file_mapping.is_empty());
609+
assert!(config.uhyve.config.is_none());
610+
assert!(config.guest.kernel == Path::new(""));
611611
}
612612

613613
/// Tests whether TOML merge works as expected.

src/hypercall.rs

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::{
1111
isolation::{
1212
fd::{FdData, GuestFd},
1313
filemap::UhyveFileMap,
14+
image::MappedFile,
1415
},
1516
mem::{MemoryError, MmapMemory},
1617
params::EnvVars,
@@ -92,8 +93,18 @@ pub fn unlink(mem: &MmapMemory, sysunlink: &mut UnlinkParams, file_map: &mut Uhy
9293
sysunlink.ret = if let Some(host_path) = file_map.get_host_path(guest_path) {
9394
// We can safely unwrap here, as host_path.as_bytes will never contain internal \0 bytes
9495
// As host_path_c_string is a valid CString, this implementation is presumed to be safe.
95-
let host_path_c_string = CString::new(host_path.as_bytes()).unwrap();
96-
unsafe { libc::unlink(host_path_c_string.as_c_str().as_ptr()) }
96+
match host_path {
97+
MappedFile::OnHost(oh) => {
98+
let host_path_c_string = CString::new(oh.as_os_str().as_bytes()).unwrap();
99+
unsafe { libc::unlink(host_path_c_string.as_c_str().as_ptr()) }
100+
}
101+
MappedFile::InImage(_) => {
102+
error!(
103+
"The kernel requested to unlink() a ROM path ({guest_path:?}): Rejecting..."
104+
);
105+
-EROFS
106+
}
107+
}
97108
} else {
98109
error!("The kernel requested to unlink() an unknown path ({guest_path:?}): Rejecting...");
99110
-ENOENT
@@ -113,20 +124,49 @@ pub fn open(mem: &MmapMemory, sysopen: &mut OpenParams, file_map: &mut UhyveFile
113124
return;
114125
}
115126

116-
sysopen.ret = if let Some(host_path) = file_map.get_host_path(guest_path) {
127+
sysopen.ret = if let Some(guest_entry) = file_map.get_host_path(guest_path) {
117128
debug!("{guest_path:#?} found in file map.");
118-
// We can safely unwrap here, as host_path.as_bytes will never contain internal \0 bytes
119-
// As host_path_c_string is a valid CString, this implementation is presumed to be safe.
120-
let host_path_c_string = CString::new(host_path.as_bytes()).unwrap();
129+
match guest_entry {
130+
MappedFile::OnHost(host_path) => {
131+
// We can safely unwrap here, as host_path.as_bytes will never contain internal \0 bytes
132+
// As host_path_c_string is a valid CString, this implementation is presumed to be safe.
133+
let host_path_c_string = CString::new(host_path.as_os_str().as_bytes()).unwrap();
121134

122-
let host_fd =
123-
unsafe { libc::open(host_path_c_string.as_c_str().as_ptr(), flags, sysopen.mode) };
124-
if let Some(guest_fd) = file_map.fdmap.insert(FdData::Raw(host_fd)) {
125-
guest_fd.0
126-
} else if host_fd < 0 {
127-
host_fd
128-
} else {
129-
-ENOENT
135+
let host_fd = unsafe {
136+
libc::open(host_path_c_string.as_c_str().as_ptr(), flags, sysopen.mode)
137+
};
138+
if let Some(guest_fd) = file_map.fdmap.insert(FdData::Raw(host_fd)) {
139+
guest_fd.0
140+
} else if host_fd < 0 {
141+
host_fd
142+
} else {
143+
-ENOENT
144+
}
145+
}
146+
MappedFile::InImage(yk) => {
147+
match yk.try_map_project(move |data, _| {
148+
if let hermit_entry::ThinTree::File { content, .. } = data {
149+
Ok(content)
150+
} else {
151+
Err(())
152+
}
153+
}) {
154+
Ok(data) => {
155+
file_map
156+
.fdmap
157+
.insert(FdData::Virtual {
158+
data: data.erase_arc_cart(),
159+
offset: 0,
160+
})
161+
.expect("virtual file fdmapping should never fail")
162+
.0
163+
}
164+
Err(()) => {
165+
debug!("Returning -EISDIR for {guest_path:#?}");
166+
-EISDIR
167+
}
168+
}
169+
}
130170
}
131171
} else {
132172
debug!("{guest_path:#?} not found in file map.");
@@ -206,6 +246,7 @@ pub fn read(
206246
amt,
207247
)
208248
};
249+
*offset += u64::try_from(amt).unwrap();
209250
amt as isize
210251
}
211252
}

0 commit comments

Comments
 (0)