diff --git a/rust/src/cliwrap.rs b/rust/src/cliwrap.rs index a514857727..9314c3a6ac 100644 --- a/rust/src/cliwrap.rs +++ b/rust/src/cliwrap.rs @@ -15,11 +15,13 @@ use std::io::prelude::*; mod cliutil; mod dracut; mod grubby; +mod kernel_install_wrap; mod rpm; mod yumdnf; use crate::cxxrsutil::CxxResult; use crate::ffi::SystemHostType; use crate::ffiutil::*; +use crate::kernel_install::is_ostree_layout; /// Location for the underlying (not wrapped) binaries. pub const CLIWRAP_DESTDIR: &str = "usr/libexec/rpm-ostree/wrapped"; @@ -30,6 +32,9 @@ static WRAPPED_BINARIES: &[&str] = &["usr/bin/rpm", "usr/bin/dracut", "usr/sbin/ /// Binaries we will wrap, or create if they don't exist. static MUSTWRAP_BINARIES: &[&str] = &["usr/bin/yum", "usr/bin/dnf"]; +/// Binaries we will wrap only if ostree layout is not specified. +static NON_OSTREE_LAYOUT_WRAP_BINARIES: &[&str] = &["usr/bin/kernel-install"]; + #[derive(Debug, PartialEq)] pub(crate) enum RunDisposition { Ok, @@ -73,6 +78,7 @@ pub fn entrypoint(args: &[&str]) -> Result<()> { "yum" | "dnf" => Ok(self::yumdnf::main(host_type, args)?), "dracut" => Ok(self::dracut::main(args)?), "grubby" => Ok(self::grubby::main(args)?), + "kernel-install" if !is_ostree_layout()? => Ok(self::kernel_install_wrap::main(args)?), _ => Err(anyhow!("Unknown wrapped binary: {}", name)), } } else { @@ -151,12 +157,21 @@ fn write_wrappers(rootfs_dfd: &Dir, allowlist: Option<&HashSet<&str>>) -> Result let all_wrapped = WRAPPED_BINARIES.iter().map(Utf8Path::new); let all_mustwrap = MUSTWRAP_BINARIES.iter().map(Utf8Path::new); - let all_names = all_wrapped + let all_non_ostree_layout_wrap = NON_OSTREE_LAYOUT_WRAP_BINARIES.iter().map(Utf8Path::new); + let mut all_names = all_wrapped .clone() .chain(all_mustwrap.clone()) .map(|p| p.file_name().unwrap()) .collect::>(); + if !is_ostree_layout()? { + all_names.extend( + all_non_ostree_layout_wrap + .clone() + .map(|p| p.file_name().unwrap()), + ); + } + if let Some(allowlist) = allowlist.as_ref() { for k in allowlist.iter() { if !all_names.contains(k) { @@ -168,7 +183,7 @@ fn write_wrappers(rootfs_dfd: &Dir, allowlist: Option<&HashSet<&str>>) -> Result let allowlist_contains = |v: &(&Utf8Path, bool)| allowlist.map_or(true, |l| l.contains(v.0.file_name().unwrap())); - WRAPPED_BINARIES + let final_binaries = WRAPPED_BINARIES .par_iter() .map(|p| (Utf8Path::new(p), true)) .chain( @@ -176,8 +191,22 @@ fn write_wrappers(rootfs_dfd: &Dir, allowlist: Option<&HashSet<&str>>) -> Result .par_iter() .map(|p| (Utf8Path::new(p), false)), ) + .chain(if !is_ostree_layout()? { + NON_OSTREE_LAYOUT_WRAP_BINARIES + .par_iter() + .map(|p| (Utf8Path::new(p), false)) + .collect::>() + .into_par_iter() + } else { + Vec::new().into_par_iter() + }); + + final_binaries .filter(allowlist_contains) - .try_for_each(|(binpath, allow_noent)| write_one_wrapper(rootfs_dfd, binpath, allow_noent)) + .try_for_each(|(binpath, allow_noent)| { + write_one_wrapper(rootfs_dfd, binpath, allow_noent) + })?; + Ok(()) } pub(crate) fn cliwrap_write_wrappers(rootfs_dfd: i32) -> CxxResult<()> { diff --git a/rust/src/cliwrap/kernel_install_wrap.rs b/rust/src/cliwrap/kernel_install_wrap.rs new file mode 100644 index 0000000000..09d86a476e --- /dev/null +++ b/rust/src/cliwrap/kernel_install_wrap.rs @@ -0,0 +1,64 @@ +// If not running on container continue the current path. +// SPDX-License-Identifier: Apache-2.0 OR MIT +use crate::cliwrap::cliutil; +use anyhow::Result; +use camino::Utf8Path; +use cap_std::fs::Dir as StdDir; +use cap_std::fs::FileType; +use cap_std::fs_utf8::Dir as Utf8Dir; +use cap_std_ext::cap_std; +use fn_error_context::context; + +/// Primary entrypoint to running our wrapped `kernel-install` handling. +#[context("rpm-ostree kernel-install wrapper")] +pub(crate) fn main(argv: &[&str]) -> Result<()> { + if !ostree_ext::container_utils::is_ostree_container()? { + return cliutil::exec_real_binary("kernel-install", argv); + } + let is_install = matches!(argv.first(), Some(&"add")); + + let modules_path = Utf8Dir::open_ambient_dir("lib/modules", cap_std::ambient_authority())?; + //kernel-install is called by kernel-core and kernel-modules cleanup let's make sure we just call dracut once. + let mut new_kernel: Option<_> = None; + + //finds which the kernel to remove and which to generate the initramfs for. + for entry in modules_path.entries()? { + let entry = entry?; + let kernel_dir = entry.file_name()?; + let kernel_binary_path = Utf8Path::new(&kernel_dir).join("vmlinuz"); + + if entry.file_type()? == FileType::dir() { + if modules_path.exists(kernel_binary_path) { + if is_install { + new_kernel = Some(kernel_dir); + } + } else { + new_kernel = None; + modules_path.remove_dir_all(kernel_dir)?; + } + } + } + if let Some(k) = new_kernel { + undo_systemctl_wrap()?; + let root_fs = StdDir::open_ambient_dir("/", cap_std::ambient_authority())?; + crate::initramfs::run_dracut(&root_fs, &k)?; + redo_systemctl_wrap()?; + } + Ok(()) +} + +#[context("Unwrapping systemctl")] +fn undo_systemctl_wrap() -> Result<()> { + let bin_path = Utf8Dir::open_ambient_dir("usr/bin", cap_std::ambient_authority())?; + bin_path.rename("systemctl", &bin_path, "systemctl.backup")?; + bin_path.rename("systemctl.rpmostreesave", &bin_path, "systemctl")?; + Ok(()) +} + +#[context("Wrapping systemctl")] +fn redo_systemctl_wrap() -> Result<()> { + let bin_path = Utf8Dir::open_ambient_dir("usr/bin", cap_std::ambient_authority())?; + bin_path.rename("systemctl", &bin_path, "systemctl.rpmostreesave")?; + bin_path.rename("systemctl.backup", &bin_path, "systemctl")?; + Ok(()) +} diff --git a/rust/src/core.rs b/rust/src/core.rs index 6285392055..bbdb11aeb2 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -49,8 +49,6 @@ const USERMOD_WRAPPER: &[u8] = include_bytes!("../../src/libpriv/usermod-wrapper const KERNEL_INSTALL_PATH: &str = "usr/bin/kernel-install"; const KERNEL_INSTALL_WRAPPER: &[u8] = include_bytes!("../../src/libpriv/kernel-install-wrapper.sh"); -// ## Check for layout and wrap if =ostree - const RPMOSTREE_CORE_STAGED_RPMS_DIR: &str = "rpm-ostree/staged-rpms"; pub(crate) const OSTREE_BOOTED: &str = "/run/ostree-booted"; @@ -171,6 +169,7 @@ impl FilesystemScriptPrep { (USERMOD_PATH, USERMOD_WRAPPER), ]; + // Separate const as is used only to wrap kernel-install if !is_ostree_layout() const REPLACE_KERNEL_PATHS: &'static [(&'static str, &'static [u8])] = &[(KERNEL_INSTALL_PATH, KERNEL_INSTALL_WRAPPER)];