Skip to content

Commit c895c61

Browse files
authored
Merge pull request #953 from omertuc/cli
install: Guide user towards the correct podman flags
2 parents 33a361c + ba9cfb6 commit c895c61

File tree

3 files changed

+34
-22
lines changed

3 files changed

+34
-22
lines changed

lib/src/cli.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::io::Seek;
77
use std::os::unix::process::CommandExt;
88
use std::process::Command;
99

10-
use anyhow::{Context, Result};
10+
use anyhow::{ensure, Context, Result};
1111
use camino::Utf8PathBuf;
1212
use cap_std_ext::cap_std;
1313
use cap_std_ext::cap_std::fs::Dir;
@@ -576,15 +576,27 @@ pub(crate) async fn get_storage() -> Result<crate::store::Storage> {
576576
}
577577

578578
#[context("Querying root privilege")]
579-
pub(crate) fn require_root() -> Result<()> {
580-
let uid = rustix::process::getuid();
581-
if !uid.is_root() {
582-
anyhow::bail!("This command requires root privileges");
583-
}
584-
if !rustix::thread::capability_is_in_bounding_set(rustix::thread::Capability::SystemAdmin)? {
585-
anyhow::bail!("This command requires full root privileges (CAP_SYS_ADMIN)");
586-
}
579+
pub(crate) fn require_root(is_container: bool) -> Result<()> {
580+
ensure!(
581+
rustix::process::getuid().is_root(),
582+
if is_container {
583+
"The user inside the container from which you are running this command must be root"
584+
} else {
585+
"This command must be executed as the root user"
586+
}
587+
);
588+
589+
ensure!(
590+
rustix::thread::capability_is_in_bounding_set(rustix::thread::Capability::SystemAdmin)?,
591+
if is_container {
592+
"The container must be executed with full privileges (e.g. --privileged flag)"
593+
} else {
594+
"This command requires full root privileges (CAP_SYS_ADMIN)"
595+
}
596+
);
597+
587598
tracing::trace!("Verified uid 0 with CAP_SYS_ADMIN");
599+
588600
Ok(())
589601
}
590602

@@ -616,7 +628,7 @@ fn prepare_for_write() -> Result<()> {
616628
ostree_booted()?,
617629
"This command requires an ostree-booted host system"
618630
);
619-
crate::cli::require_root()?;
631+
crate::cli::require_root(false)?;
620632
ensure_self_unshared_mount_namespace()?;
621633
if crate::lsm::selinux_enabled()? && !crate::lsm::selinux_ensure_install()? {
622634
tracing::warn!("Do not have install_t capabilities");

lib/src/install.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,7 +1003,7 @@ pub(crate) fn finalize_filesystem(
10031003
/// A heuristic check that we were invoked with --pid=host
10041004
fn require_host_pidns() -> Result<()> {
10051005
if rustix::process::getpid().is_init() {
1006-
anyhow::bail!("This command must be run with --pid=host")
1006+
anyhow::bail!("This command must be run with the podman --pid=host flag")
10071007
}
10081008
tracing::trace!("OK: we're not pid 1");
10091009
Ok(())
@@ -1019,9 +1019,7 @@ fn require_host_userns() -> Result<()> {
10191019
.uid();
10201020
// We must really be in a rootless container, or in some way
10211021
// we're not part of the host user namespace.
1022-
if pid1_uid != 0 {
1023-
anyhow::bail!("{proc1} is owned by {pid1_uid}, not zero; this command must be run in the root user namespace (e.g. not rootless podman)");
1024-
}
1022+
ensure!(pid1_uid == 0, "{proc1} is owned by {pid1_uid}, not zero; this command must be run in the root user namespace (e.g. not rootless podman)");
10251023
tracing::trace!("OK: we're in a matching user namespace with pid1");
10261024
Ok(())
10271025
}
@@ -1154,18 +1152,17 @@ async fn prepare_install(
11541152
target_opts: InstallTargetOpts,
11551153
) -> Result<Arc<State>> {
11561154
tracing::trace!("Preparing install");
1157-
// We need full root privileges, i.e. --privileged in podman
1158-
crate::cli::require_root()?;
11591155
let rootfs = cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())
11601156
.context("Opening /")?;
11611157

11621158
let host_is_container = crate::containerenv::is_container(&rootfs);
11631159
let external_source = source_opts.source_imgref.is_some();
11641160
let source = match source_opts.source_imgref {
11651161
None => {
1166-
if !host_is_container {
1167-
anyhow::bail!("Either --source-imgref must be defined or this command must be executed inside a podman container.")
1168-
}
1162+
ensure!(host_is_container, "Either --source-imgref must be defined or this command must be executed inside a podman container.");
1163+
1164+
crate::cli::require_root(true)?;
1165+
11691166
require_host_pidns()?;
11701167
// Out of conservatism we only verify the host userns path when we're expecting
11711168
// to do a self-install (e.g. not bootc-image-builder or equivalent).
@@ -1187,7 +1184,10 @@ async fn prepare_install(
11871184

11881185
SourceInfo::from_container(&rootfs, &container_info)?
11891186
}
1190-
Some(source) => SourceInfo::from_imageref(&source, &rootfs)?,
1187+
Some(source) => {
1188+
crate::cli::require_root(false)?;
1189+
SourceInfo::from_imageref(&source, &rootfs)?
1190+
}
11911191
};
11921192

11931193
// Parse the target CLI image reference options and create the *target* image

lib/src/install/completion.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ pub(crate) async fn run_from_anaconda(rootfs: &Dir) -> Result<()> {
197197
// unshare our mount namespace, so any *further* mounts aren't leaked.
198198
// Note that because this does a re-exec, anything *before* this point
199199
// should be idempotent.
200-
crate::cli::require_root()?;
200+
crate::cli::require_root(false)?;
201201
crate::cli::ensure_self_unshared_mount_namespace()?;
202202

203203
if std::env::var_os(ANACONDA_ENV_HINT).is_none() {
@@ -245,7 +245,7 @@ pub(crate) async fn run_from_anaconda(rootfs: &Dir) -> Result<()> {
245245

246246
/// From ostree-rs-ext, run through the rest of bootc install functionality
247247
pub async fn run_from_ostree(rootfs: &Dir, sysroot: &Utf8Path, stateroot: &str) -> Result<()> {
248-
crate::cli::require_root()?;
248+
crate::cli::require_root(false)?;
249249
// Load sysroot from the provided path
250250
let sysroot = ostree::Sysroot::new(Some(&gio::File::for_path(sysroot)));
251251
sysroot.load(gio::Cancellable::NONE)?;

0 commit comments

Comments
 (0)