Skip to content

Commit b89d788

Browse files
committed
api: krun_set_init takes static binary only
Signed-off-by: Geoffrey Goodman <geoff@goodman.dev>
1 parent 496baaf commit b89d788

8 files changed

Lines changed: 28 additions & 72 deletions

File tree

include/libkrun.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,10 @@ int32_t krun_set_root(uint32_t ctx_id, const char *root_path);
112112
/**
113113
* Sets the init binary payload that will be exposed as /init.krun inside the guest.
114114
*
115-
* The payload is copied when this API is called. It will be used for /dev/root
116-
* virtio-fs devices configured in this context.
115+
* IMPORTANT LIFETIME CONTRACT:
116+
* The memory range [init_binary, init_binary + init_binary_len) is NOT copied.
117+
* The caller MUST keep that memory valid and unchanged for the full VM lifetime
118+
* in this context (until krun_start_enter() returns and the VM is torn down).
117119
*
118120
* Arguments:
119121
* "ctx_id" - the configuration context ID.

src/devices/src/virtio/fs/device.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ use super::super::{
1717
};
1818
use super::passthrough;
1919
use super::worker::FsWorker;
20+
use super::ExportTable;
2021
use super::{defs, defs::uapi};
21-
use super::{ExportTable, InitPayload};
2222
use crate::virtio::InterruptTransport;
2323

2424
#[derive(Copy, Clone)]
@@ -59,7 +59,7 @@ impl Fs {
5959
shared_dir: String,
6060
exit_code: Arc<AtomicI32>,
6161
allow_root_dir_delete: bool,
62-
init_payload: Option<InitPayload>,
62+
init_payload: Option<&'static [u8]>,
6363
) -> super::Result<Fs> {
6464
let avail_features = (1u64 << VIRTIO_F_VERSION_1) | (1u64 << VIRTIO_RING_F_EVENT_IDX);
6565

src/devices/src/virtio/fs/linux/passthrough.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use super::super::filesystem::{
2626
};
2727
use super::super::fuse;
2828
use super::super::multikey::MultikeyBTreeMap;
29-
use super::super::InitPayload;
3029

3130
const CURRENT_DIR_CSTR: &[u8] = b".\0";
3231
const PARENT_DIR_CSTR: &[u8] = b"..\0";
@@ -327,7 +326,7 @@ pub struct Config {
327326
/// Table of exported FDs to share with other subsystems.
328327
pub export_table: Option<ExportTable>,
329328
pub allow_root_dir_delete: bool,
330-
pub init_payload: Option<InitPayload>,
329+
pub init_payload: Option<&'static [u8]>,
331330
}
332331

333332
impl Default for Config {
@@ -462,11 +461,7 @@ impl PassthroughFs {
462461
}
463462

464463
fn init_payload(&self) -> io::Result<&[u8]> {
465-
self.cfg
466-
.init_payload
467-
.as_ref()
468-
.map(InitPayload::as_slice)
469-
.ok_or_else(ebadf)
464+
self.cfg.init_payload.ok_or_else(ebadf)
470465
}
471466

472467
fn open_inode(&self, inode: Inode, mut flags: i32) -> io::Result<File> {

src/devices/src/virtio/fs/macos/passthrough.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ use super::super::filesystem::{
3030
};
3131
use super::super::fuse;
3232
use super::super::multikey::MultikeyBTreeMap;
33-
use super::super::InitPayload;
3433

3534
const INIT_CSTR: &[u8] = b"init.krun\0";
3635
const XATTR_KEY: &[u8] = b"user.containers.override_stat\0";
@@ -516,7 +515,7 @@ pub struct Config {
516515
/// Table of exported FDs to share with other subsystems. Not supported for macos.
517516
pub export_table: Option<ExportTable>,
518517
pub allow_root_dir_delete: bool,
519-
pub init_payload: Option<InitPayload>,
518+
pub init_payload: Option<&'static [u8]>,
520519
}
521520

522521
impl Default for Config {
@@ -600,11 +599,7 @@ impl PassthroughFs {
600599
}
601600

602601
fn init_payload(&self) -> io::Result<&[u8]> {
603-
self.cfg
604-
.init_payload
605-
.as_ref()
606-
.map(InitPayload::as_slice)
607-
.ok_or_else(ebadf)
602+
self.cfg.init_payload.ok_or_else(ebadf)
608603
}
609604

610605
fn inode_to_handle(&self, inode: Inode, supports_fd: bool) -> io::Result<InodeHandle> {

src/devices/src/virtio/fs/mod.rs

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,35 +27,6 @@ pub use self::defs::uapi::VIRTIO_ID_FS as TYPE_FS;
2727
pub use self::device::Fs;
2828
pub use self::filesystem::ExportTable;
2929

30-
/// Payload backing for the synthetic `/init.krun` file exposed by virtio-fs.
31-
///
32-
/// We support two storage modes:
33-
/// - `Static` for any compile-time embedded payload (for example via
34-
/// `include_bytes!`), including but not limited to libkrun's default init.
35-
/// This keeps the common embedded case zero-copy.
36-
/// - `Owned` for runtime-provided bytes (for example from the C API), where we
37-
/// must not borrow caller memory.
38-
///
39-
/// This keeps read paths uniform via `as_slice()` while preserving zero-copy for
40-
/// embedded payloads and safe ownership for dynamic payload injection.
41-
#[derive(Clone, Debug)]
42-
pub enum InitPayload {
43-
/// Compile-time embedded payload (`&'static [u8]`) with zero-copy use.
44-
Static(&'static [u8]),
45-
/// Runtime-provided payload with owned, reference-counted backing storage.
46-
Owned(Arc<[u8]>),
47-
}
48-
49-
impl InitPayload {
50-
/// View the payload as a byte slice regardless of backing representation.
51-
pub fn as_slice(&self) -> &[u8] {
52-
match self {
53-
InitPayload::Static(bytes) => bytes,
54-
InitPayload::Owned(bytes) => bytes,
55-
}
56-
}
57-
}
58-
5930
mod defs {
6031
use super::super::QueueConfig;
6132

@@ -75,7 +46,6 @@ mod defs {
7546

7647
use std::ffi::{FromBytesWithNulError, FromVecWithNulError};
7748
use std::io;
78-
use std::sync::Arc;
7949

8050
use descriptor_utils::Error as DescriptorError;
8151

src/libkrun/src/lib.rs

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ use env_logger::{Env, Target};
1414
#[cfg(feature = "gpu")]
1515
use krun_display::DisplayBackend;
1616

17-
#[cfg(not(feature = "tee"))]
18-
use devices::virtio::fs::InitPayload;
1917
use libc::{c_char, c_int, size_t};
2018
use once_cell::sync::Lazy;
2119
use polly::event_manager::EventManager;
@@ -36,8 +34,6 @@ use std::os::fd::{BorrowedFd, FromRawFd, RawFd};
3634
use std::path::PathBuf;
3735
use std::slice;
3836
use std::sync::atomic::{AtomicI32, Ordering};
39-
#[cfg(not(any(feature = "tee", feature = "aws-nitro")))]
40-
use std::sync::Arc;
4137
use std::sync::{LazyLock, Mutex};
4238
use utils::eventfd::EventFd;
4339
use vmm::resources::{
@@ -94,7 +90,7 @@ static KRUNFW: LazyLock<Option<libloading::Library>> =
9490
LazyLock::new(|| unsafe { libloading::Library::new(KRUNFW_NAME).ok() });
9591

9692
#[cfg(not(any(feature = "tee", feature = "aws-nitro")))]
97-
const DEFAULT_INIT_PAYLOAD: InitPayload = InitPayload::Static(krun_init::DEFAULT_INIT);
93+
const DEFAULT_INIT_PAYLOAD: &[u8] = krun_init::DEFAULT_INIT;
9894

9995
pub struct KrunfwBindings {
10096
get_kernel: libloading::Symbol<
@@ -171,7 +167,7 @@ struct ContextConfig {
171167
vmm_uid: Option<libc::uid_t>,
172168
vmm_gid: Option<libc::gid_t>,
173169
#[cfg(not(feature = "tee"))]
174-
init_payload: Option<InitPayload>,
170+
init_payload: Option<&'static [u8]>,
175171
}
176172

177173
impl ContextConfig {
@@ -241,13 +237,13 @@ impl ContextConfig {
241237
}
242238

243239
#[cfg(not(feature = "tee"))]
244-
fn set_init_payload(&mut self, init_payload: InitPayload) {
245-
self.init_payload = Some(init_payload);
240+
fn set_init_binary(&mut self, init_binary: &'static [u8]) {
241+
self.init_payload = Some(init_binary);
246242
}
247243

248244
#[cfg(not(feature = "tee"))]
249-
fn get_init_payload(&self) -> InitPayload {
250-
self.init_payload.clone().unwrap_or(DEFAULT_INIT_PAYLOAD)
245+
fn get_init_binary(&self) -> &'static [u8] {
246+
self.init_payload.unwrap_or(DEFAULT_INIT_PAYLOAD)
251247
}
252248

253249
fn get_args(&self) -> String {
@@ -613,7 +609,7 @@ pub unsafe extern "C" fn krun_set_root(ctx_id: u32, c_root_path: *const c_char)
613609
// Default to a conservative 512 MB window.
614610
shm_size: Some(1 << 29),
615611
allow_root_dir_delete: false,
616-
init_payload: Some(cfg.get_init_payload()),
612+
init_payload: Some(cfg.get_init_binary()),
617613
});
618614
}
619615
Entry::Vacant(_) => return -libc::ENOENT,
@@ -634,18 +630,18 @@ pub unsafe extern "C" fn krun_set_init(
634630
return -libc::EINVAL;
635631
}
636632

637-
let payload = InitPayload::Owned(Arc::<[u8]>::from(slice::from_raw_parts(
638-
init_binary,
639-
init_binary_len,
640-
)));
633+
// SAFETY CONTRACT: The caller guarantees that this memory range remains
634+
// valid for the full VM lifetime (until krun_start_enter() returns and the
635+
// context is dropped). We do not copy the bytes.
636+
let payload: &'static [u8] = slice::from_raw_parts(init_binary, init_binary_len);
641637

642638
match CTX_MAP.lock().unwrap().entry(ctx_id) {
643639
Entry::Occupied(mut ctx_cfg_entry) => {
644640
let ctx_cfg = ctx_cfg_entry.get_mut();
645-
ctx_cfg.set_init_payload(payload.clone());
641+
ctx_cfg.set_init_binary(payload);
646642

647643
for fs_cfg in &mut ctx_cfg.vmr.fs {
648-
fs_cfg.init_payload = Some(payload.clone());
644+
fs_cfg.init_payload = Some(payload);
649645
}
650646
}
651647
Entry::Vacant(_) => return -libc::ENOENT,
@@ -679,7 +675,7 @@ pub unsafe extern "C" fn krun_add_virtiofs(
679675
shared_dir: path.to_string(),
680676
shm_size: None,
681677
allow_root_dir_delete: false,
682-
init_payload: Some(cfg.get_init_payload()),
678+
init_payload: Some(cfg.get_init_binary()),
683679
});
684680
}
685681
Entry::Vacant(_) => return -libc::ENOENT,
@@ -714,7 +710,7 @@ pub unsafe extern "C" fn krun_add_virtiofs2(
714710
shared_dir: path.to_string(),
715711
shm_size: Some(shm_size.try_into().unwrap()),
716712
allow_root_dir_delete: false,
717-
init_payload: Some(cfg.get_init_payload()),
713+
init_payload: Some(cfg.get_init_binary()),
718714
});
719715
}
720716
Entry::Vacant(_) => return -libc::ENOENT,
@@ -2347,7 +2343,7 @@ pub unsafe extern "C" fn krun_set_root_disk_remount(
23472343
// Default to a conservative 512 MB window.
23482344
shm_size: Some(1 << 29),
23492345
allow_root_dir_delete: true,
2350-
init_payload: Some(ctx_cfg.get_init_payload()),
2346+
init_payload: Some(ctx_cfg.get_init_binary()),
23512347
});
23522348

23532349
ctx_cfg.set_block_root(device, fstype, options);

src/vmm/src/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1911,7 +1911,7 @@ fn attach_fs_devices(
19111911
config.shared_dir.clone(),
19121912
exit_code.clone(),
19131913
config.allow_root_dir_delete,
1914-
config.init_payload.clone(),
1914+
config.init_payload,
19151915
)
19161916
.unwrap(),
19171917
));

src/vmm/src/vmm_config/fs.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
use devices::virtio::fs::InitPayload;
2-
31
#[derive(Clone, Debug)]
42
pub struct FsDeviceConfig {
53
pub fs_id: String,
64
pub shared_dir: String,
75
pub shm_size: Option<usize>,
86
pub allow_root_dir_delete: bool,
9-
pub init_payload: Option<InitPayload>,
7+
pub init_payload: Option<&'static [u8]>,
108
}

0 commit comments

Comments
 (0)