From 5446c89bc0e467d3769cd5dd2c85478f19b10b18 Mon Sep 17 00:00:00 2001 From: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com> Date: Fri, 19 Dec 2025 23:26:15 -0700 Subject: [PATCH] don't create src dir on readonly bind mount (#3084) --- core/startos/src/disk/mount/filesystem/bind.rs | 7 ++++--- core/startos/src/disk/mount/filesystem/ecryptfs.rs | 2 +- core/startos/src/disk/mount/filesystem/idmapped.rs | 5 +++-- core/startos/src/disk/mount/filesystem/mod.rs | 8 ++++++-- core/startos/src/disk/mount/filesystem/overlayfs.rs | 4 ++-- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/core/startos/src/disk/mount/filesystem/bind.rs b/core/startos/src/disk/mount/filesystem/bind.rs index c48bcbf84..87458410d 100644 --- a/core/startos/src/disk/mount/filesystem/bind.rs +++ b/core/startos/src/disk/mount/filesystem/bind.rs @@ -8,6 +8,7 @@ use sha2::Sha256; use ts_rs::TS; use super::FileSystem; +use crate::disk::mount::filesystem::MountType; use crate::prelude::*; use crate::util::io::create_file; @@ -48,7 +49,7 @@ impl + Send + Sync> FileSystem for Bind { fn extra_args(&self) -> impl IntoIterator> { ["--bind"] } - async fn pre_mount(&self, mountpoint: &Path) -> Result<(), Error> { + async fn pre_mount(&self, mountpoint: &Path, mount_type: MountType) -> Result<(), Error> { let from_meta = tokio::fs::metadata(&self.src).await.ok(); let to_meta = tokio::fs::metadata(&mountpoint).await.ok(); if matches!(self.filetype, FileType::File) @@ -58,7 +59,7 @@ impl + Send + Sync> FileSystem for Bind { if to_meta.as_ref().map_or(false, |m| m.is_dir()) { tokio::fs::remove_dir(mountpoint).await?; } - if from_meta.is_none() { + if from_meta.is_none() && mount_type == MountType::ReadWrite { create_file(self.src.as_ref()).await?.sync_all().await?; } if to_meta.is_none() { @@ -68,7 +69,7 @@ impl + Send + Sync> FileSystem for Bind { if to_meta.as_ref().map_or(false, |m| m.is_file()) { tokio::fs::remove_file(mountpoint).await?; } - if from_meta.is_none() { + if from_meta.is_none() && mount_type == MountType::ReadWrite { tokio::fs::create_dir_all(self.src.as_ref()).await?; } if to_meta.is_none() { diff --git a/core/startos/src/disk/mount/filesystem/ecryptfs.rs b/core/startos/src/disk/mount/filesystem/ecryptfs.rs index bc1a0b65b..f98f092c6 100644 --- a/core/startos/src/disk/mount/filesystem/ecryptfs.rs +++ b/core/startos/src/disk/mount/filesystem/ecryptfs.rs @@ -49,7 +49,7 @@ impl + Send + Sync, Key: AsRef + Send + Sync> Fil mountpoint: P, mount_type: super::MountType, ) -> Result<(), Error> { - self.pre_mount(mountpoint.as_ref()).await?; + self.pre_mount(mountpoint.as_ref(), mount_type).await?; Command::new("mount") .args( default_mount_command(self, mountpoint, mount_type) diff --git a/core/startos/src/disk/mount/filesystem/idmapped.rs b/core/startos/src/disk/mount/filesystem/idmapped.rs index 0a351b313..87a59760c 100644 --- a/core/startos/src/disk/mount/filesystem/idmapped.rs +++ b/core/startos/src/disk/mount/filesystem/idmapped.rs @@ -14,6 +14,7 @@ use tokio::process::Command; use ts_rs::TS; use super::FileSystem; +use crate::disk::mount::filesystem::MountType; use crate::prelude::*; use crate::util::{FromStrParser, Invoke}; @@ -110,8 +111,8 @@ impl FileSystem for IdMapped { async fn source(&self) -> Result>, Error> { self.filesystem.source().await } - async fn pre_mount(&self, mountpoint: &Path) -> Result<(), Error> { - self.filesystem.pre_mount(mountpoint).await?; + async fn pre_mount(&self, mountpoint: &Path, mount_type: MountType) -> Result<(), Error> { + self.filesystem.pre_mount(mountpoint, mount_type).await?; let info = tokio::fs::metadata(mountpoint).await?; for i in &self.idmap { let uid_in_range = i.from_id <= info.uid() && i.from_id + i.range > info.uid(); diff --git a/core/startos/src/disk/mount/filesystem/mod.rs b/core/startos/src/disk/mount/filesystem/mod.rs index ac37f2217..80f79a3a4 100644 --- a/core/startos/src/disk/mount/filesystem/mod.rs +++ b/core/startos/src/disk/mount/filesystem/mod.rs @@ -69,7 +69,7 @@ pub(self) async fn default_mount_impl( mountpoint: impl AsRef + Send, mount_type: MountType, ) -> Result<(), Error> { - fs.pre_mount(mountpoint.as_ref()).await?; + fs.pre_mount(mountpoint.as_ref(), mount_type).await?; Command::from(default_mount_command(fs, mountpoint, mount_type).await?) .capture(false) .invoke(ErrorKind::Filesystem) @@ -91,7 +91,11 @@ pub trait FileSystem: Send + Sync { fn source(&self) -> impl Future>, Error>> + Send { async { Ok(None::<&Path>) } } - fn pre_mount(&self, mountpoint: &Path) -> impl Future> + Send { + fn pre_mount( + &self, + mountpoint: &Path, + #[allow(unused_variables)] mount_type: MountType, + ) -> impl Future> + Send { async move { tokio::fs::create_dir_all(mountpoint).await?; Ok(()) diff --git a/core/startos/src/disk/mount/filesystem/overlayfs.rs b/core/startos/src/disk/mount/filesystem/overlayfs.rs index 09a7d953b..d743589dd 100644 --- a/core/startos/src/disk/mount/filesystem/overlayfs.rs +++ b/core/startos/src/disk/mount/filesystem/overlayfs.rs @@ -6,7 +6,7 @@ use digest::generic_array::GenericArray; use digest::{Digest, OutputSizeUser}; use sha2::Sha256; -use crate::disk::mount::filesystem::{FileSystem, ReadWrite}; +use crate::disk::mount::filesystem::{FileSystem, MountType, ReadWrite}; use crate::disk::mount::guard::{GenericMountGuard, MountGuard}; use crate::prelude::*; use crate::util::io::TmpDir; @@ -38,7 +38,7 @@ impl + Send + Sync, P1: AsRef + Send + Sync, P2: AsRef Result<(), Error> { + async fn pre_mount(&self, mountpoint: &Path, _: MountType) -> Result<(), Error> { tokio::fs::create_dir_all(self.upper.as_ref()).await?; tokio::fs::create_dir_all(self.work.as_ref()).await?; tokio::fs::create_dir_all(mountpoint).await?;