From 89588ef525fe1d6bb88d95a3de533a7a515999ed Mon Sep 17 00:00:00 2001 From: djach7 Date: Mon, 30 Sep 2024 09:56:11 -0400 Subject: [PATCH] Check for existing mounts when installing to disk Signed-off-by: djach7 --- lib/src/install.rs | 1 + lib/src/install/baseline.rs | 6 ++++++ lib/src/mount.rs | 41 ++++++++++++++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/lib/src/install.rs b/lib/src/install.rs index d244f5a90..29e747081 100644 --- a/lib/src/install.rs +++ b/lib/src/install.rs @@ -1802,6 +1802,7 @@ fn test_gather_root_args() { maj_min: "252:4".into(), options: "rw".into(), uuid: Some("965eb3c7-5a3f-470d-aaa2-1bcf04334bc6".into()), + children: None, }; let r = find_root_args_to_inherit(&[], &inspect).unwrap(); assert_eq!(r.mount_spec, "UUID=965eb3c7-5a3f-470d-aaa2-1bcf04334bc6"); diff --git a/lib/src/install/baseline.rs b/lib/src/install/baseline.rs index f7c1c3540..b92eef457 100644 --- a/lib/src/install/baseline.rs +++ b/lib/src/install/baseline.rs @@ -27,6 +27,7 @@ use super::State; use super::RUN_BOOTC; use super::RW_KARG; use crate::mount; +use crate::mount::is_mounted_in_pid1_mountns; use crate::task::Task; // This ensures we end up under 512 to be small-sized. @@ -162,6 +163,11 @@ pub(crate) fn install_create_rootfs( // Canonicalize devpath let devpath: Utf8PathBuf = device.path().into(); + // Always disallow writing to mounted device + if is_mounted_in_pid1_mountns(&device.path())? { + anyhow::bail!("Device {} is mounted", device.path()) + } + // Handle wiping any existing data if opts.wipe { let dev = &opts.device; diff --git a/lib/src/mount.rs b/lib/src/mount.rs index da5af05c0..825229339 100644 --- a/lib/src/mount.rs +++ b/lib/src/mount.rs @@ -12,6 +12,7 @@ use crate::task::Task; #[derive(Deserialize, Debug)] #[serde(rename_all = "kebab-case")] +#[allow(dead_code)] pub(crate) struct Filesystem { // Note if you add an entry to this list, you need to change the --output invocation below too pub(crate) source: String, @@ -21,6 +22,7 @@ pub(crate) struct Filesystem { pub(crate) fstype: String, pub(crate) options: String, pub(crate) uuid: Option, + pub(crate) children: Option>, } #[derive(Deserialize, Debug)] @@ -28,7 +30,7 @@ pub(crate) struct Findmnt { pub(crate) filesystems: Vec, } -fn run_findmnt(args: &[&str], path: &str) -> Result { +fn run_findmnt(args: &[&str], path: &str) -> Result { let o: Findmnt = Command::new("findmnt") .args([ "-J", @@ -40,6 +42,12 @@ fn run_findmnt(args: &[&str], path: &str) -> Result { .arg(path) .log_debug() .run_and_parse_json()?; + Ok(o) +} + +// Retrieve a mounted filesystem from a device given a matching path +fn findmnt_filesystem(args: &[&str], path: &str) -> Result { + let o = run_findmnt(args, path)?; o.filesystems .into_iter() .next() @@ -50,13 +58,40 @@ fn run_findmnt(args: &[&str], path: &str) -> Result { /// Inspect a target which must be a mountpoint root - it is an error /// if the target is not the mount root. pub(crate) fn inspect_filesystem(path: &Utf8Path) -> Result { - run_findmnt(&["--mountpoint"], path.as_str()) + findmnt_filesystem(&["--mountpoint"], path.as_str()) } #[context("Inspecting filesystem by UUID {uuid}")] /// Inspect a filesystem by partition UUID pub(crate) fn inspect_filesystem_by_uuid(uuid: &str) -> Result { - run_findmnt(&["--source"], &(format!("UUID={uuid}"))) + findmnt_filesystem(&["--source"], &(format!("UUID={uuid}"))) +} + +// Check if a specified device contains an already mounted filesystem +// in the root mount namespace +pub(crate) fn is_mounted_in_pid1_mountns(path: &str) -> Result { + let o = run_findmnt(&["-N"], "1")?; + + let mounted = o.filesystems.iter().any(|fs| is_source_mounted(path, fs)); + + Ok(mounted) +} + +// Recursively check a given filesystem to see if it contains an already mounted source +pub(crate) fn is_source_mounted(path: &str, mounted_fs: &Filesystem) -> bool { + if mounted_fs.source.contains(path) { + return true; + } + + if let Some(ref children) = mounted_fs.children { + for child in children { + if is_source_mounted(path, child) { + return true; + } + } + } + + false } /// Mount a device to the target path.