From 07810bf71ff0088c6412df04aaeec1e87aa29b33 Mon Sep 17 00:00:00 2001 From: Zvonko Kaiser Date: Tue, 30 May 2023 15:38:54 +0000 Subject: [PATCH] agent: Ignore already mounted dev/fs/pseudo-fs Using an initrd and setting KATA_INIT=yes meaning we're using the kata-agent as the init process we need to make sure that the agent is not segfaulting if mounts are already happened. Some workloads need to configure several things in the initrd before the kata-agent starts which involves having /proc or /sys already mounted. Fixes: #6992 Signed-off-by: Zvonko Kaiser --- src/agent/src/mount.rs | 66 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/agent/src/mount.rs b/src/agent/src/mount.rs index 5b0d95c19c..b3cf101709 100644 --- a/src/agent/src/mount.rs +++ b/src/agent/src/mount.rs @@ -145,6 +145,11 @@ pub const STORAGE_HANDLER_LIST: &[&str] = &[ DRIVER_WATCHABLE_BIND_TYPE, ]; +#[instrument] +pub fn get_mounts() -> Result { + fs::read_to_string("/proc/mounts") +} + #[instrument] pub fn baremount( source: &Path, @@ -168,6 +173,31 @@ pub fn baremount( return Err(anyhow!("need mount FS type")); } + let destination_str = destination.to_string_lossy(); + let mounts = get_mounts().unwrap_or_else(|_| String::new()); + let already_mounted = mounts + .lines() + .map(|line| line.split_whitespace().collect::>()) + .filter(|parts| parts.len() >= 3) // ensure we have at least [source}, destination, and fs_type + .any(|parts| { + // Check if source, destination and fs_type match any entry in /proc/mounts + // minimal check is for destination an fstype since source can have different names like: + // udev /dev devtmpfs + // dev /dev devtmpfs + // depending on which entity is mounting the dev/fs/pseudo-fs + parts[1] == destination_str && parts[2] == fs_type + }); + + if already_mounted { + slog_info!( + logger, + "{:?} is already mounted at {:?}", + source, + destination + ); + return Ok(()); + } + info!( logger, "baremount source={:?}, dest={:?}, fs_type={:?}, options={:?}, flags={:?}", @@ -1112,6 +1142,42 @@ mod tests { skip_if_not_root, skip_loop_by_user, skip_loop_if_not_root, skip_loop_if_root, }; + // Shadow get_mounts during tests since this is only used in the test + // context, compiler will warn about dead-code. + #[allow(dead_code)] + fn get_mounts() -> Result { + Ok(String::from( + " + rootfs / rootfs rw,size=1694984k,nr_inodes=423746 0 0 + proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0 + sys /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0 + dev /dev devtmpfs rw,nosuid,relatime,size=1695000k,nr_inodes=423750,mode=755 0 0 + run /run tmpfs rw,nosuid,nodev,relatime,mode=755 0 0 + ", + )) + } + + #[test] + fn test_already_baremounted() { + let drain = slog::Discard; + let logger = slog::Logger::root(drain, o!()); + let test_cases = [ + ("dev", "/dev", "devtmpfs"), + ("udev", "/dev", "devtmpfs"), + ("proc", "/proc", "proc"), + ("sysfs", "/sys", "sysfs"), + ]; + + for &(source, destination, fs_type) in &test_cases { + let source = Path::new(source); + let destination = Path::new(destination); + let flags = MsFlags::MS_RDONLY; + let options = "mode=755"; + println!("baremount({:?} {:?} {:?}", source, destination, fs_type); + assert!(baremount(source, destination, fs_type, flags, options, &logger).is_ok()); + } + } + #[test] fn test_mount() { #[derive(Debug)]