Skip to content

Commit 4d816fa

Browse files
authored
Merge pull request #805 from djach7/installToDisk
install-to-disk: Check for mounts before install
2 parents 33fcf92 + 89588ef commit 4d816fa

File tree

3 files changed

+45
-3
lines changed

3 files changed

+45
-3
lines changed

lib/src/install.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1802,6 +1802,7 @@ fn test_gather_root_args() {
18021802
maj_min: "252:4".into(),
18031803
options: "rw".into(),
18041804
uuid: Some("965eb3c7-5a3f-470d-aaa2-1bcf04334bc6".into()),
1805+
children: None,
18051806
};
18061807
let r = find_root_args_to_inherit(&[], &inspect).unwrap();
18071808
assert_eq!(r.mount_spec, "UUID=965eb3c7-5a3f-470d-aaa2-1bcf04334bc6");

lib/src/install/baseline.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use super::State;
2727
use super::RUN_BOOTC;
2828
use super::RW_KARG;
2929
use crate::mount;
30+
use crate::mount::is_mounted_in_pid1_mountns;
3031
use crate::task::Task;
3132

3233
// This ensures we end up under 512 to be small-sized.
@@ -162,6 +163,11 @@ pub(crate) fn install_create_rootfs(
162163
// Canonicalize devpath
163164
let devpath: Utf8PathBuf = device.path().into();
164165

166+
// Always disallow writing to mounted device
167+
if is_mounted_in_pid1_mountns(&device.path())? {
168+
anyhow::bail!("Device {} is mounted", device.path())
169+
}
170+
165171
// Handle wiping any existing data
166172
if opts.wipe {
167173
let dev = &opts.device;

lib/src/mount.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::task::Task;
1212

1313
#[derive(Deserialize, Debug)]
1414
#[serde(rename_all = "kebab-case")]
15+
#[allow(dead_code)]
1516
pub(crate) struct Filesystem {
1617
// Note if you add an entry to this list, you need to change the --output invocation below too
1718
pub(crate) source: String,
@@ -21,14 +22,15 @@ pub(crate) struct Filesystem {
2122
pub(crate) fstype: String,
2223
pub(crate) options: String,
2324
pub(crate) uuid: Option<String>,
25+
pub(crate) children: Option<Vec<Filesystem>>,
2426
}
2527

2628
#[derive(Deserialize, Debug)]
2729
pub(crate) struct Findmnt {
2830
pub(crate) filesystems: Vec<Filesystem>,
2931
}
3032

31-
fn run_findmnt(args: &[&str], path: &str) -> Result<Filesystem> {
33+
fn run_findmnt(args: &[&str], path: &str) -> Result<Findmnt> {
3234
let o: Findmnt = Command::new("findmnt")
3335
.args([
3436
"-J",
@@ -40,6 +42,12 @@ fn run_findmnt(args: &[&str], path: &str) -> Result<Filesystem> {
4042
.arg(path)
4143
.log_debug()
4244
.run_and_parse_json()?;
45+
Ok(o)
46+
}
47+
48+
// Retrieve a mounted filesystem from a device given a matching path
49+
fn findmnt_filesystem(args: &[&str], path: &str) -> Result<Filesystem> {
50+
let o = run_findmnt(args, path)?;
4351
o.filesystems
4452
.into_iter()
4553
.next()
@@ -50,13 +58,40 @@ fn run_findmnt(args: &[&str], path: &str) -> Result<Filesystem> {
5058
/// Inspect a target which must be a mountpoint root - it is an error
5159
/// if the target is not the mount root.
5260
pub(crate) fn inspect_filesystem(path: &Utf8Path) -> Result<Filesystem> {
53-
run_findmnt(&["--mountpoint"], path.as_str())
61+
findmnt_filesystem(&["--mountpoint"], path.as_str())
5462
}
5563

5664
#[context("Inspecting filesystem by UUID {uuid}")]
5765
/// Inspect a filesystem by partition UUID
5866
pub(crate) fn inspect_filesystem_by_uuid(uuid: &str) -> Result<Filesystem> {
59-
run_findmnt(&["--source"], &(format!("UUID={uuid}")))
67+
findmnt_filesystem(&["--source"], &(format!("UUID={uuid}")))
68+
}
69+
70+
// Check if a specified device contains an already mounted filesystem
71+
// in the root mount namespace
72+
pub(crate) fn is_mounted_in_pid1_mountns(path: &str) -> Result<bool> {
73+
let o = run_findmnt(&["-N"], "1")?;
74+
75+
let mounted = o.filesystems.iter().any(|fs| is_source_mounted(path, fs));
76+
77+
Ok(mounted)
78+
}
79+
80+
// Recursively check a given filesystem to see if it contains an already mounted source
81+
pub(crate) fn is_source_mounted(path: &str, mounted_fs: &Filesystem) -> bool {
82+
if mounted_fs.source.contains(path) {
83+
return true;
84+
}
85+
86+
if let Some(ref children) = mounted_fs.children {
87+
for child in children {
88+
if is_source_mounted(path, child) {
89+
return true;
90+
}
91+
}
92+
}
93+
94+
false
6095
}
6196

6297
/// Mount a device to the target path.

0 commit comments

Comments
 (0)