Skip to content

Commit 84cd0f8

Browse files
committed
install: Never traverse mount points with --wipe
If we encounter a mount point when attempting to wipe a filesystem, then something has definitely gone wrong. At the install phase we should only be operating on a single physical filesystem. Signed-off-by: Colin Walters <[email protected]>
1 parent a442ac2 commit 84cd0f8

File tree

1 file changed

+21
-16
lines changed

1 file changed

+21
-16
lines changed

lib/src/install.rs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use camino::Utf8Path;
2828
use camino::Utf8PathBuf;
2929
use cap_std::fs::{Dir, MetadataExt};
3030
use cap_std_ext::cap_std;
31+
use cap_std_ext::cap_std::fs::FileType;
3132
use cap_std_ext::cap_std::fs_utf8::DirEntry as DirEntryUtf8;
3233
use cap_std_ext::cap_tempfile::TempDir;
3334
use cap_std_ext::cmdext::CapStdExtCommandExt;
@@ -56,7 +57,7 @@ use crate::progress_jsonl::ProgressWriter;
5657
use crate::spec::ImageReference;
5758
use crate::store::Storage;
5859
use crate::task::Task;
59-
use crate::utils::sigpolicy_from_opts;
60+
use crate::utils::{open_dir_noxdev, sigpolicy_from_opts};
6061

6162
/// The toplevel boot directory
6263
const BOOT: &str = "boot";
@@ -1558,14 +1559,22 @@ fn require_empty_rootdir(rootfs_fd: &Dir) -> Result<()> {
15581559
}
15591560

15601561
/// Remove all entries in a directory, but do not traverse across distinct devices.
1562+
/// If mount_err is true, then an error is returned if a mount point is found;
1563+
/// otherwise it is silently ignored.
15611564
#[context("Removing entries (noxdev)")]
1562-
fn remove_all_in_dir_no_xdev(d: &Dir) -> Result<()> {
1563-
let parent_dev = d.dir_metadata()?.dev();
1565+
fn remove_all_in_dir_no_xdev(d: &Dir, mount_err: bool) -> Result<()> {
15641566
for entry in d.entries()? {
15651567
let entry = entry?;
1566-
let entry_dev = entry.metadata()?.dev();
1567-
if entry_dev == parent_dev {
1568-
d.remove_all_optional(entry.file_name())?;
1568+
let name = entry.file_name();
1569+
let etype = entry.file_type()?;
1570+
if etype == FileType::dir() {
1571+
if let Some(subdir) = open_dir_noxdev(d, &name)? {
1572+
remove_all_in_dir_no_xdev(&subdir, mount_err)?;
1573+
} else if mount_err {
1574+
anyhow::bail!("Found unexpected mount point {name:?}");
1575+
}
1576+
} else {
1577+
d.remove_file_optional(&name)?;
15691578
}
15701579
}
15711580
anyhow::Ok(())
@@ -1576,13 +1585,15 @@ fn clean_boot_directories(rootfs: &Dir) -> Result<()> {
15761585
let bootdir =
15771586
crate::utils::open_dir_remount_rw(rootfs, BOOT.into()).context("Opening /boot")?;
15781587
// This should not remove /boot/efi note.
1579-
remove_all_in_dir_no_xdev(&bootdir)?;
1588+
remove_all_in_dir_no_xdev(&bootdir, false)?;
1589+
// TODO: Discover the ESP the same way bootupd does it; we should also
1590+
// support not wiping the ESP.
15801591
if ARCH_USES_EFI {
15811592
if let Some(efidir) = bootdir
15821593
.open_dir_optional(crate::bootloader::EFI_DIR)
15831594
.context("Opening /boot/efi")?
15841595
{
1585-
remove_all_in_dir_no_xdev(&efidir)?;
1596+
remove_all_in_dir_no_xdev(&efidir, false)?;
15861597
}
15871598
}
15881599
Ok(())
@@ -1730,14 +1741,8 @@ pub(crate) async fn install_to_filesystem(
17301741
Some(ReplaceMode::Wipe) => {
17311742
let rootfs_fd = rootfs_fd.try_clone()?;
17321743
println!("Wiping contents of root");
1733-
tokio::task::spawn_blocking(move || {
1734-
for e in rootfs_fd.entries()? {
1735-
let e = e?;
1736-
rootfs_fd.remove_all_optional(e.file_name())?;
1737-
}
1738-
anyhow::Ok(())
1739-
})
1740-
.await??;
1744+
tokio::task::spawn_blocking(move || remove_all_in_dir_no_xdev(&rootfs_fd, true))
1745+
.await??;
17411746
}
17421747
Some(ReplaceMode::Alongside) => clean_boot_directories(&rootfs_fd)?,
17431748
None => require_empty_rootdir(&rootfs_fd)?,

0 commit comments

Comments
 (0)