From 408f16eea1230c1e26e2a4e4cf252a865358f1af Mon Sep 17 00:00:00 2001 From: "Brad P. Crochet" Date: Tue, 6 Feb 2024 16:53:28 +0000 Subject: [PATCH] Ensure that efivarfs is mounted in the container Especially on ARM, which utilizes UEFI for booting in most cases, it is important that the /sys/firmware/efi/efivars be mounted and populated, otherwise bootc will fail to complete a to-filesystem installation. This patch attempts a mount as long as the hosts efivars directory has an entry, signifying the system is at least capable of UEFI. Note that it is sufficient to just attempt to mount efivars. If it's already mounted elsewhere, it triggers the mount to be made at the /sys location. Fixes #291 Signed-off-by: Brad P. Crochet --- lib/src/install.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/lib/src/install.rs b/lib/src/install.rs index c75083abe..c40226fdd 100644 --- a/lib/src/install.rs +++ b/lib/src/install.rs @@ -14,6 +14,7 @@ use std::io::BufWriter; use std::io::Write; use std::os::fd::AsFd; use std::os::unix::process::CommandExt; +use std::path::Path; use std::process::Command; use std::str::FromStr; use std::sync::Arc; @@ -859,6 +860,44 @@ pub(crate) fn setup_tmp_mounts() -> Result<()> { Ok(()) } +/// By default, podman/docker etc. when passed `--privileged` mount `/sys` as read-only, +/// but non-recursively. We selectively grab sub-filesystems that we need. +#[context("Ensuring sys mounts")] +pub(crate) fn setup_sys_mounts() -> Result<()> { + tracing::debug!("Setting up sys mounts"); + + let root_efivars = "/sys/firmware/efi/efivars"; + let efivars = format!("/proc/1/root/{root_efivars}"); + // Does efivars even exist in the host? If not, we are + // not dealing with an EFI system + if !Path::new(efivars.as_str()).try_exists()? { + return Ok(()); + } + + // Now, let's find out if it's populated + if std::fs::read_dir(efivars)?.next().is_none() { + return Ok(()); + } + + // First of all, does the container already have the mount? + let path = Utf8Path::new(root_efivars); + if path.try_exists()? { + tracing::debug!("Check if efivarfs already mount"); + let inspect = crate::mount::inspect_filesystem(path); + if inspect.is_ok() { + tracing::trace!("Already have efivarfs {root_efivars}"); + return Ok(()); + } + } + + // This means the host has this mounted, so we should mount it too + Task::new_and_run( + "Mounting efivarfs /sys/firmware/efi/efivars", + "mount", + ["-t", "efivarfs", "efivars", "/sys/firmware/efi/efivars"], + ) +} + /// Verify that we can load the manifest of the target image #[context("Verifying fetch")] async fn verify_target_fetch(imgref: &ostree_container::OstreeImageReference) -> Result<()> { @@ -954,6 +993,8 @@ async fn prepare_install( super::cli::ensure_self_unshared_mount_namespace().await?; } + setup_sys_mounts()?; + // Now, deal with SELinux state. let (override_disable_selinux, setenforce_guard) = reexecute_self_for_selinux_if_needed(&source, config_opts.disable_selinux)?;