Skip to content

Commit

Permalink
WIP: Try to have both wrapped kernel-install and our impl
Browse files Browse the repository at this point in the history
  • Loading branch information
jmarrero committed Dec 20, 2024
1 parent 36a51a2 commit ca3d005
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 5 deletions.
35 changes: 32 additions & 3 deletions rust/src/cliwrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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::<HashSet<_>>();

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) {
Expand All @@ -168,16 +183,30 @@ 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(
MUSTWRAP_BINARIES
.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::<Vec<_>>()
.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<()> {
Expand Down
64 changes: 64 additions & 0 deletions rust/src/cliwrap/kernel_install_wrap.rs
Original file line number Diff line number Diff line change
@@ -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(())
}
3 changes: 1 addition & 2 deletions rust/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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)];

Expand Down

0 comments on commit ca3d005

Please sign in to comment.