Skip to content

Commit e122757

Browse files
committed
feat(isolation): minimal support for Hermit image tar files
Note that this is only the backend support, it doesn't expose that functionality to end-users of the `uhyve` binary.
1 parent 0a923a9 commit e122757

File tree

6 files changed

+49
-37
lines changed

6 files changed

+49
-37
lines changed

Cargo.lock

Lines changed: 1 addition & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ libc = "0.2"
4949
log = "0.4"
5050
mac_address = "1.1"
5151
nix = { version = "0.31", features = ["mman", "pthread", "signal"] }
52+
tar-no-std = { version = "0.4", features = ["alloc"] }
5253
thiserror = "2.0.18"
5354
time = "0.3"
5455
tun-tap = { version = "0.1.3", default-features = false }
@@ -66,7 +67,6 @@ uuid = { version = "1.20.0", features = ["fast-rng", "v4"]}
6667
toml = "1"
6768
serde = { version = "1.0", features = ["derive"] }
6869
merge = "0.2"
69-
yoke = "0.8"
7070
nohash = "0.2"
7171

7272
[target.'cfg(target_os = "linux")'.dependencies]

src/hypercall.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,6 @@ pub fn read(
309309
}
310310
}
311311
FdData::Virtual { data, offset } => {
312-
let data: &[u8] = data.get();
313312
let remaining = {
314313
let pos = cmp::min(*offset, data.len() as u64);
315314
&data[pos as usize..]
@@ -463,7 +462,7 @@ pub fn lseek(syslseek: &mut LseekParams, file_map: &mut UhyveFileMap) {
463462
let tmp: i64 = match syslseek.whence as i32 {
464463
SEEK_SET => 0,
465464
SEEK_CUR => *offset as i64,
466-
SEEK_END => data.get().len() as i64,
465+
SEEK_END => data.len() as i64,
467466
_ => -EINVAL as i64,
468467
};
469468
if tmp >= 0 {

src/isolation/fd.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ use std::{
33
fmt,
44
hash::BuildHasherDefault,
55
os::fd::{FromRawFd, OwnedFd, RawFd},
6+
sync::Arc,
67
};
78

89
use nohash::NoHashHasher;
9-
use yoke::{Yoke, erased::ErasedArcCart};
1010

1111
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1212
pub struct GuestFd(pub i32);
@@ -48,21 +48,17 @@ pub enum FdData {
4848
Raw(RawFd),
4949

5050
#[allow(dead_code)]
51-
/// An in-memory slice (possibly mmap-ed)
51+
/// An in-memory slice.
5252
///
5353
/// SAFETY: It is not allowed for `data` to point into guest memory.
54-
Virtual {
55-
data: Yoke<&'static [u8], ErasedArcCart>,
56-
offset: u64,
57-
},
54+
Virtual { data: Arc<[u8]>, offset: u64 },
5855
}
5956

6057
impl fmt::Debug for FdData {
6158
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6259
match self {
6360
FdData::Raw(r) => write!(f, "Raw({r})"),
6461
FdData::Virtual { data, offset } => {
65-
let data = data.get();
6662
let data_snip = &data[..core::cmp::min(10, data.len())];
6763
write!(f, "Virtual({data_snip:?} @ {offset})")
6864
}

src/isolation/filemap/mod.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::{
22
ffi::{CStr, CString, OsString},
33
os::unix::ffi::OsStrExt,
44
path::PathBuf,
5+
sync::Arc,
56
};
67

78
#[cfg(target_os = "linux")]
@@ -54,6 +55,19 @@ impl From<Option<String>> for UhyveIoMode {
5455
}
5556
}
5657

58+
#[derive(Clone, Debug, thiserror::Error)]
59+
pub enum HermitImageError {
60+
#[error("The Hermit image tar file is corrupted: {0}")]
61+
CorruptData(#[from] tar_no_std::CorruptDataError),
62+
63+
#[error("A file in the Hermit image doesn't have an UTF-8 file name: {0:?}")]
64+
// NOTE: `Box`ed to avoid too large size differences between enum entries.
65+
NonUtf8Filename(Box<tar_no_std::TarFormatString<256>>),
66+
67+
#[error("Unable to create a file from the Hermit image in the directory tree: {0:?}")]
68+
CreateFile(String),
69+
}
70+
5771
/// Wrapper around a `HashMap` to map guest paths to arbitrary host paths and track file descriptors.
5872
#[derive(Debug)]
5973
pub struct UhyveFileMap {
@@ -96,6 +110,32 @@ impl UhyveFileMap {
96110
fm
97111
}
98112

113+
/// Adds the contents of a decompressed hermit image to the file map.
114+
#[allow(unused)]
115+
pub fn add_hermit_image(&mut self, tar_bytes: &[u8]) -> Result<(), HermitImageError> {
116+
if tar_bytes.is_empty() {
117+
return Ok(());
118+
}
119+
120+
for i in tar_no_std::TarArchiveRef::new(tar_bytes)?.entries() {
121+
let filename = i.filename();
122+
let filename = filename
123+
.as_str()
124+
.map_err(|_| HermitImageError::NonUtf8Filename(Box::new(filename)))?;
125+
let data: Arc<[u8]> = i.data().to_vec().into();
126+
127+
// UNWRAP: `tar_no_std::ArchiveEntry::filename` already truncates at the first null byte.
128+
if !self.create_file(
129+
&CString::new(filename).unwrap(),
130+
UhyveTreeFile::Virtual(data),
131+
) {
132+
return Err(HermitImageError::CreateFile(filename.to_string()));
133+
}
134+
}
135+
136+
Ok(())
137+
}
138+
99139
/// Returns the host_path on the host filesystem given a requested guest_path, if it exists.
100140
///
101141
/// * `guest_path` - The guest path that is to be looked up in the map.

src/isolation/filemap/tree.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ use std::{
44
fmt, fs,
55
os::unix::ffi::OsStrExt,
66
path::{Path, PathBuf},
7+
sync::Arc,
78
};
89

9-
use yoke::{Yoke, erased::ErasedArcCart};
10-
1110
pub type Directory = HashMap<Box<str>, Tree>;
1211

1312
/// A virtual file, which can either resolve to an on-host path or a virtual read-only file.
@@ -18,14 +17,14 @@ pub enum File {
1817

1918
/// An in-memory file
2019
#[allow(unused)]
21-
Virtual(Yoke<&'static [u8], ErasedArcCart>),
20+
Virtual(Arc<[u8]>),
2221
}
2322

2423
impl fmt::Debug for File {
2524
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2625
match self {
2726
Self::OnHost(hp) => write!(f, "OnHost({:?})", hp),
28-
Self::Virtual(_) => write!(f, "Virtual(..)"),
27+
Self::Virtual(slice) => write!(f, "Virtual(len={})", slice.len()),
2928
}
3029
}
3130
}

0 commit comments

Comments
 (0)