Skip to content

Commit 00ef86e

Browse files
WhatAmISupposedToPutHereslp
authored andcommitted
Stop leaking muvm configuration into vm environment
Signed-off-by: Sasha Finkelstein <[email protected]>
1 parent 365d7d6 commit 00ef86e

8 files changed

Lines changed: 115 additions & 144 deletions

File tree

crates/muvm/src/bin/muvm.rs

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::collections::HashMap;
12
use std::env;
23
use std::ffi::{c_char, CString};
34
use std::io::Write;
@@ -21,23 +22,24 @@ use muvm::launch::{launch_or_lock, LaunchResult, DYNAMIC_PORT_RANGE};
2122
use muvm::monitor::spawn_monitor;
2223
use muvm::net::{connect_to_passt, start_passt};
2324
use muvm::types::MiB;
25+
use muvm::utils::launch::{GuestConfiguration, Launch};
2426
use nix::sys::sysinfo::sysinfo;
2527
use nix::unistd::User;
2628
use rustix::io::Errno;
2729
use rustix::process::{
2830
geteuid, getgid, getrlimit, getuid, sched_setaffinity, setrlimit, CpuSet, Resource,
2931
};
30-
use serde::{Deserialize, Serialize};
32+
use serde::Serialize;
3133
use tempfile::NamedTempFile;
3234

33-
#[derive(Serialize, Deserialize)]
35+
#[derive(Serialize)]
3436
pub struct KrunConfig {
3537
#[serde(rename = "Cmd")]
3638
args: Vec<String>,
3739
#[serde(rename = "Env")]
3840
envs: Vec<String>,
3941
}
40-
#[derive(Serialize, Deserialize)]
42+
#[derive(Serialize)]
4143
pub struct KrunBaseConfig {
4244
#[serde(rename = "Config")]
4345
config: KrunConfig,
@@ -223,13 +225,10 @@ fn main() -> Result<ExitCode> {
223225
.collect()
224226
};
225227

226-
if options.merged_rootfs {
227-
if disks.is_empty() {
228-
return Err(anyhow!(
229-
"Merged RootFS mode requires one or more RootFS images"
230-
));
231-
}
232-
env.insert("FEX_MERGEDROOTFS".to_owned(), "1".to_owned());
228+
if options.merged_rootfs && disks.is_empty() {
229+
return Err(anyhow!(
230+
"Merged RootFS mode requires one or more RootFS images"
231+
));
233232
}
234233

235234
for path in disks {
@@ -385,55 +384,67 @@ fn main() -> Result<ExitCode> {
385384

386385
let muvm_guest_path = find_muvm_exec("muvm-guest")?;
387386

388-
let mut muvm_guest_args: Vec<String> = vec![
387+
let display = env::var("DISPLAY").ok();
388+
let guest_config = GuestConfiguration {
389+
command: Launch {
390+
cookie,
391+
command,
392+
command_args,
393+
env: HashMap::new(),
394+
vsock_port: 0,
395+
tty: false,
396+
privileged: false,
397+
},
398+
server_port: options.server_port,
399+
username,
400+
uid: getuid().as_raw(),
401+
gid: getgid().as_raw(),
402+
host_display: display,
403+
server_cookie: cookie,
404+
merged_rootfs: options.merged_rootfs,
405+
};
406+
let mut muvm_config_file = NamedTempFile::new()
407+
.context("Failed to create a temporary file to store the muvm guest config")?;
408+
write!(
409+
muvm_config_file,
410+
"{}",
411+
serde_json::to_string(&guest_config)
412+
.context("Failed to transform GuestConfiguration into a JSON string")?
413+
)
414+
.context("Failed to write to temporary config file")?;
415+
416+
let muvm_config_path = muvm_config_file
417+
.path()
418+
.to_str()
419+
.context("Temporary directory path contains invalid UTF-8")?
420+
.to_owned();
421+
let muvm_guest_args = vec![
389422
muvm_guest_path
390423
.to_str()
391424
.context("Failed to process `muvm-guest` path as it contains invalid UTF-8")?
392425
.to_owned(),
393-
username,
394-
format!("{uid}", uid = getuid().as_raw()),
395-
format!("{gid}", gid = getgid().as_raw()),
396-
command
397-
.to_str()
398-
.context("Failed to process command as it contains invalid UTF-8")?
399-
.to_string(),
426+
muvm_config_path,
400427
];
401-
for arg in command_args {
402-
muvm_guest_args.push(arg);
403-
}
404-
405-
env.insert(
406-
"MUVM_SERVER_PORT".to_owned(),
407-
options.server_port.to_string(),
408-
);
409-
env.insert("MUVM_SERVER_COOKIE".to_owned(), cookie.to_string());
410-
411-
let display = env::var("DISPLAY").context("X11 forwarding requested but DISPLAY is unset")?;
412-
env.insert("HOST_DISPLAY".to_string(), display);
413428

414429
// And forward XAUTHORITY. This will be modified to fix the
415430
// display name in muvm-guest.
416431
if let Ok(xauthority) = env::var("XAUTHORITY") {
417-
env.insert("XAUTHORITY".to_string(), xauthority);
432+
env.insert("XAUTHORITY".to_owned(), xauthority);
418433
}
419434

420-
let mut krun_config = KrunConfig {
421-
args: Vec::new(),
422-
envs: Vec::new(),
423-
};
424-
for arg in muvm_guest_args {
425-
krun_config.args.push(arg);
426-
}
427-
for (key, value) in env {
428-
krun_config.envs.push(format!("{}={}", key, value));
429-
}
430435
let krun_config = KrunBaseConfig {
431-
config: krun_config,
436+
config: KrunConfig {
437+
args: muvm_guest_args,
438+
envs: env
439+
.into_iter()
440+
.map(|(key, value)| format!("{key}={value}"))
441+
.collect(),
442+
},
432443
};
433444

434445
// SAFETY: `config_file` lifetime needs to exceed krun_start_enter's
435446
let mut config_file = NamedTempFile::new()
436-
.context("Failed to create a temporary file to store the guest config")?;
447+
.context("Failed to create a temporary file to store the krun config")?;
437448
write!(
438449
config_file,
439450
"{}",

crates/muvm/src/guest/bin/muvm-guest.rs

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
use std::fs::File;
2+
use std::io::Read;
13
use std::os::fd::AsFd;
24
use std::panic::catch_unwind;
35
use std::process::Command;
4-
use std::{cmp, env, thread};
6+
use std::{cmp, env, fs, thread};
57

68
use anyhow::{Context, Result};
7-
use muvm::guest::cli_options::options;
89
use muvm::guest::fex::setup_fex;
910
use muvm::guest::hidpipe::start_hidpipe;
1011
use muvm::guest::mount::mount_filesystems;
@@ -14,8 +15,12 @@ use muvm::guest::socket::setup_socket_proxy;
1415
use muvm::guest::user::setup_user;
1516
use muvm::guest::x11::setup_x11_forwarding;
1617
use muvm::guest::x11bridge::start_x11bridge;
18+
use muvm::utils::launch::GuestConfiguration;
19+
use nix::unistd::{Gid, Uid};
1720
use rustix::process::{getrlimit, setrlimit, Resource};
1821

22+
const KRUN_CONFIG: &str = "KRUN_CONFIG";
23+
1924
fn main() -> Result<()> {
2025
env_logger::init();
2126

@@ -24,7 +29,22 @@ fn main() -> Result<()> {
2429
return Ok(());
2530
}
2631

27-
let options = options().run();
32+
let config_path = env::args()
33+
.nth(1)
34+
.context("expected configuration file path")?;
35+
let mut config_file = File::open(&config_path)?;
36+
let mut config_buf = Vec::new();
37+
config_file.read_to_end(&mut config_buf)?;
38+
fs::remove_file(config_path).context("Unable to delete temporary muvm configuration file")?;
39+
if let Ok(krun_config_path) = env::var(KRUN_CONFIG) {
40+
fs::remove_file(krun_config_path)
41+
.context("Unable to delete temporary krun configuration file")?;
42+
// SAFETY: We are single-threaded at this point
43+
env::remove_var(KRUN_CONFIG);
44+
}
45+
// SAFETY: We are single-threaded at this point
46+
env::remove_var("KRUN_WORKDIR");
47+
let options = serde_json::from_slice::<GuestConfiguration>(&config_buf)?;
2848

2949
{
3050
const ESYNC_RLIMIT_NOFILE: u64 = 524288;
@@ -41,7 +61,7 @@ fn main() -> Result<()> {
4161
setrlimit(Resource::Nofile, rlim).context("Failed to raise `RLIMIT_NOFILE`")?;
4262
}
4363

44-
if let Err(err) = mount_filesystems() {
64+
if let Err(err) = mount_filesystems(options.merged_rootfs) {
4565
return Err(err).context("Failed to mount filesystems, bailing out");
4666
}
4767

@@ -61,7 +81,11 @@ fn main() -> Result<()> {
6181

6282
configure_network()?;
6383

64-
let run_path = match setup_user(options.username, options.uid, options.gid) {
84+
let run_path = match setup_user(
85+
options.username,
86+
Uid::from(options.uid),
87+
Gid::from(options.gid),
88+
) {
6589
Ok(p) => p,
6690
Err(err) => return Err(err).context("Failed to set up user, bailing out"),
6791
};
@@ -72,9 +96,11 @@ fn main() -> Result<()> {
7296
let pulse_path = pulse_path.join("native");
7397
setup_socket_proxy(pulse_path, 3333)?;
7498

75-
setup_x11_forwarding(run_path)?;
99+
if let Some(host_display) = options.host_display {
100+
setup_x11_forwarding(run_path, &host_display)?;
101+
}
76102

77-
let uid = options.uid.as_raw();
103+
let uid = options.uid;
78104
thread::spawn(move || {
79105
if catch_unwind(|| start_hidpipe(uid)).is_err() {
80106
eprintln!("hidpipe thread crashed, input device passthrough will no longer function");
@@ -83,6 +109,12 @@ fn main() -> Result<()> {
83109

84110
let rt = tokio::runtime::Runtime::new().unwrap();
85111
rt.block_on(async {
86-
server_main(options.server_port, options.command, options.command_args).await
112+
server_main(
113+
options.server_port,
114+
options.server_cookie,
115+
options.command.command,
116+
options.command.command_args,
117+
)
118+
.await
87119
})
88120
}

crates/muvm/src/guest/cli_options.rs

Lines changed: 0 additions & 62 deletions
This file was deleted.

crates/muvm/src/guest/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
pub mod cli_options;
21
pub mod fex;
32
pub mod hidpipe;
43
pub mod mount;

crates/muvm/src/guest/mount.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::collections::HashSet;
2-
use std::env;
32
use std::ffi::CString;
43
use std::fs::{read_dir, read_link, File};
54
use std::io::Write;
@@ -50,7 +49,7 @@ fn do_mount_recursive_bind(source: &str, target: PathBuf) -> Result<()> {
5049
Ok(())
5150
}
5251

53-
fn mount_fex_rootfs() -> Result<()> {
52+
fn mount_fex_rootfs(merged_rootfs: bool) -> Result<()> {
5453
let dir = "/run/fex-emu/";
5554
let dir_rootfs = dir.to_string() + "rootfs";
5655

@@ -60,10 +59,6 @@ fn mount_fex_rootfs() -> Result<()> {
6059
let flags = MountFlags::RDONLY;
6160
let mut images = Vec::new();
6261

63-
let merged_rootfs = env::var("FEX_MERGEDROOTFS")
64-
.map(|a| a != "0")
65-
.unwrap_or(false);
66-
6762
// In merged RootFS mode, make /run/fex-emu a tmpfs.
6863
// This ensures that once /run is bind-mounted into the
6964
// rootfs, /run/fex-emu/* isn't itself visible within the
@@ -95,11 +90,7 @@ fn mount_fex_rootfs() -> Result<()> {
9590
if images.is_empty() {
9691
// If no images were passed, FEX is either managed by the host os
9792
// or is not installed at all. Avoid clobbering the config in that case.
98-
// merged_rootfs is ignored in this case, and we unset the env var so
99-
// the state of MergedRootFS is strictly managed by the host config.
100-
// TODO: Remove once #134 is merged, move merged_rootfs to config.
101-
// SAFETY: muvm-guest is single-threaded.
102-
unsafe { env::remove_var("FEX_MERGEDROOTFS") };
93+
// merged_rootfs is ignored in this case.
10394
return Ok(());
10495
}
10596

@@ -285,7 +276,7 @@ pub fn place_file(backing: &str, dest: &str, contents: Option<&str>) -> Result<(
285276
overlay_file(backing, dest)
286277
}
287278

288-
pub fn mount_filesystems() -> Result<()> {
279+
pub fn mount_filesystems(merged_rootfs: bool) -> Result<()> {
289280
make_tmpfs("/var/run")?;
290281

291282
place_file("/run/resolv.conf", "/etc/resolv.conf", None)?;
@@ -323,7 +314,7 @@ pub fn mount_filesystems() -> Result<()> {
323314
.context("Failed to mount `/dev/shm`")?;
324315

325316
// Do this last so it can pick up all the submounts made above.
326-
if let Err(e) = mount_fex_rootfs() {
317+
if let Err(e) = mount_fex_rootfs(merged_rootfs) {
327318
println!(
328319
"Failed to mount FEX rootfs, carrying on without. Error: {}",
329320
e

0 commit comments

Comments
 (0)