From e835d978ad57877eb81939828d42be2fc469c9a3 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 4 Dec 2023 16:28:01 -0500 Subject: [PATCH] Split out a `hostexec` module We'll use this even in cases where we don't have the `install` feature. Signed-off-by: Colin Walters --- lib/src/blockdev.rs | 2 +- lib/src/cli.rs | 2 +- lib/src/hostexec.rs | 38 ++++++++++++++++++++++++++++++++++++++ lib/src/install.rs | 32 +------------------------------- lib/src/lib.rs | 1 + lib/src/podman.rs | 2 +- 6 files changed, 43 insertions(+), 34 deletions(-) create mode 100644 lib/src/hostexec.rs diff --git a/lib/src/blockdev.rs b/lib/src/blockdev.rs index f6683e3e..310d4b22 100644 --- a/lib/src/blockdev.rs +++ b/lib/src/blockdev.rs @@ -1,4 +1,4 @@ -use crate::install::run_in_host_mountns; +use crate::hostexec::run_in_host_mountns; use crate::task::Task; use anyhow::{anyhow, Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; diff --git a/lib/src/cli.rs b/lib/src/cli.rs index 623796a4..e9cad5a0 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -634,7 +634,7 @@ async fn run_from_opt(opt: Opt) -> Result<()> { }, #[cfg(feature = "install")] Opt::ExecInHostMountNamespace { args } => { - crate::install::exec_in_host_mountns(args.as_slice()) + crate::hostexec::exec_in_host_mountns(args.as_slice()) } Opt::Status(opts) => super::status::status(opts).await, Opt::Internals(opts) => match opts { diff --git a/lib/src/hostexec.rs b/lib/src/hostexec.rs new file mode 100644 index 00000000..aeb347f4 --- /dev/null +++ b/lib/src/hostexec.rs @@ -0,0 +1,38 @@ +//! Run a command in the host mount namespace + +use std::os::fd::AsFd; +use std::os::unix::process::CommandExt; +use std::process::Command; + +use anyhow::{Context, Result}; +use camino::Utf8Path; +use fn_error_context::context; + +/// Run a command in the host mount namespace +pub(crate) fn run_in_host_mountns(cmd: &str) -> Command { + let mut c = Command::new("/proc/self/exe"); + c.args(["exec-in-host-mount-namespace", cmd]); + c +} + +#[context("Re-exec in host mountns")] +pub(crate) fn exec_in_host_mountns(args: &[std::ffi::OsString]) -> Result<()> { + let (cmd, args) = args + .split_first() + .ok_or_else(|| anyhow::anyhow!("Missing command"))?; + tracing::trace!("{cmd:?} {args:?}"); + let pid1mountns = std::fs::File::open("/proc/1/ns/mnt").context("open pid1 mountns")?; + nix::sched::setns(pid1mountns.as_fd(), nix::sched::CloneFlags::CLONE_NEWNS).context("setns")?; + rustix::process::chdir("/").context("chdir")?; + // Work around supermin doing chroot() and not pivot_root + // https://github.com/libguestfs/supermin/blob/5230e2c3cd07e82bd6431e871e239f7056bf25ad/init/init.c#L288 + if !Utf8Path::new("/usr").try_exists().context("/usr")? + && Utf8Path::new("/root/usr") + .try_exists() + .context("/root/usr")? + { + tracing::debug!("Using supermin workaround"); + rustix::process::chroot("/root").context("chroot")?; + } + Err(Command::new(cmd).args(args).exec()).context("exec")? +} diff --git a/lib/src/install.rs b/lib/src/install.rs index 5519ecc6..d1085ebd 100644 --- a/lib/src/install.rs +++ b/lib/src/install.rs @@ -12,9 +12,7 @@ pub(crate) mod osconfig; 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; @@ -39,6 +37,7 @@ use serde::{Deserialize, Serialize}; use self::baseline::InstallBlockDeviceOpts; use crate::containerenv::ContainerExecutionInfo; +use crate::hostexec::run_in_host_mountns; use crate::mount::Filesystem; use crate::task::Task; use crate::utils::sigpolicy_from_opts; @@ -702,35 +701,6 @@ async fn initialize_ostree_root_from_self( Ok(aleph) } -/// Run a command in the host mount namespace -pub(crate) fn run_in_host_mountns(cmd: &str) -> Command { - let mut c = Command::new("/proc/self/exe"); - c.args(["exec-in-host-mount-namespace", cmd]); - c -} - -#[context("Re-exec in host mountns")] -pub(crate) fn exec_in_host_mountns(args: &[std::ffi::OsString]) -> Result<()> { - let (cmd, args) = args - .split_first() - .ok_or_else(|| anyhow::anyhow!("Missing command"))?; - tracing::trace!("{cmd:?} {args:?}"); - let pid1mountns = std::fs::File::open("/proc/1/ns/mnt").context("open pid1 mountns")?; - nix::sched::setns(pid1mountns.as_fd(), nix::sched::CloneFlags::CLONE_NEWNS).context("setns")?; - rustix::process::chdir("/").context("chdir")?; - // Work around supermin doing chroot() and not pivot_root - // https://github.com/libguestfs/supermin/blob/5230e2c3cd07e82bd6431e871e239f7056bf25ad/init/init.c#L288 - if !Utf8Path::new("/usr").try_exists().context("/usr")? - && Utf8Path::new("/root/usr") - .try_exists() - .context("/root/usr")? - { - tracing::debug!("Using supermin workaround"); - rustix::process::chroot("/root").context("chroot")?; - } - Err(Command::new(cmd).args(args).exec()).context("exec")? -} - #[context("Querying skopeo version")] fn require_skopeo_with_containers_storage() -> Result<()> { let out = Task::new_cmd("skopeo --version", run_in_host_mountns("skopeo")) diff --git a/lib/src/lib.rs b/lib/src/lib.rs index b04d3364..b91437a4 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -20,6 +20,7 @@ pub mod cli; pub(crate) mod deploy; pub(crate) mod generator; +pub(crate) mod hostexec; pub(crate) mod journal; mod lsm; pub(crate) mod metadata; diff --git a/lib/src/podman.rs b/lib/src/podman.rs index f5f7fd96..24b659c0 100644 --- a/lib/src/podman.rs +++ b/lib/src/podman.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Result}; use serde::Deserialize; -use crate::install::run_in_host_mountns; +use crate::hostexec::run_in_host_mountns; use crate::task::Task; /// Where we look inside our container to find our own image