From 208595d59700c9d14c6ab218f6662c8a58ded05d Mon Sep 17 00:00:00 2001 From: "Brad P. Crochet" Date: Mon, 25 Mar 2024 21:22:38 -0400 Subject: [PATCH] Stop if /dev is not a bind mount with loopback At container start, /dev is snapshotted, so any new device files don't get added unless /dev is bindmounted in. For now, check that /dev is the same as the host's /dev via fsid. If they differ, it means that /dev is not bindmounted. Fixes #352 Signed-off-by: Brad P. Crochet --- lib/src/install.rs | 3 +++ lib/src/mount.rs | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/lib/src/install.rs b/lib/src/install.rs index 96002fb62..a06502415 100644 --- a/lib/src/install.rs +++ b/lib/src/install.rs @@ -1177,6 +1177,9 @@ pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> { block_opts.device ); } + if !crate::mount::is_same_as_host(Utf8Path::new("/dev"))? { + anyhow::bail!("Loopback mounts (--via-loopback) require host devices (-v /dev:/dev)"); + } } else if !target_blockdev_meta.file_type().is_block_device() { anyhow::bail!("Not a block device: {}", block_opts.device); } diff --git a/lib/src/mount.rs b/lib/src/mount.rs index 431d4f13f..3c789dcb4 100644 --- a/lib/src/mount.rs +++ b/lib/src/mount.rs @@ -57,3 +57,25 @@ pub(crate) fn mount(dev: &str, target: &Utf8Path) -> Result<()> { [dev, target.as_str()], ) } + +/// If the fsid of the passed path matches the fsid of the same path rooted +/// at /proc/1/root, it is assumed that these are indeed the same mounted +/// filesystem between container and host. +/// Path should be absolute. +#[context("Comparing filesystems at {path} and /proc/1/root/{path}")] +pub(crate) fn is_same_as_host(path: &Utf8Path) -> Result { + // Add a leading '/' in case a relative path is passed + let path = Utf8Path::new("/").join(path); + + // Using statvfs instead of fs, since rustix will translate the fsid field + // for us. + let devstat = rustix::fs::statvfs(path.as_std_path())?; + let hostpath = Utf8Path::new("/proc/1/root").join(path.strip_prefix("/")?); + let hostdevstat = rustix::fs::statvfs(hostpath.as_std_path())?; + tracing::trace!( + "base mount id {:?}, host mount id {:?}", + devstat.f_fsid, + hostdevstat.f_fsid + ); + Ok(devstat.f_fsid == hostdevstat.f_fsid) +}