From 8c6307b52d1923dca51479dc63eb80b4e4ec683a Mon Sep 17 00:00:00 2001 From: gursewak1997 Date: Thu, 9 Jul 2026 16:40:05 -0700 Subject: [PATCH] ostree-ext: Keep CAP_DAC_READ_SEARCH when passing auth via fd When running under systemd, ostree-ext drops privileges to 'nobody' with setpriv --bounding-set -all. However, skopeo needs to re-open auth file descriptors at /proc/self/fd/N, which requires CAP_DAC_READ_SEARCH. Fix by conditionally keeping this capability when auth_data is present: setpriv --bounding-set -all,+dac_read_search This fixes Anaconda installations with authenticated registries while maintaining security (still runs as unprivileged user). Signed-off-by: gursewak1997 --- crates/ostree-ext/src/container/mod.rs | 6 +++++- crates/ostree-ext/src/isolation.rs | 20 ++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/crates/ostree-ext/src/container/mod.rs b/crates/ostree-ext/src/container/mod.rs index 3419bdf82..21d12b2a0 100644 --- a/crates/ostree-ext/src/container/mod.rs +++ b/crates/ostree-ext/src/container/mod.rs @@ -471,7 +471,11 @@ pub fn merge_default_container_proxy_opts_with_isolation( if let Some(authfile) = config.authfile.take() { config.auth_data = Some(std::fs::File::open(authfile)?); } - let cmd = crate::isolation::unprivileged_subprocess(bootc_utils::skopeo_bin(), user); + // When passing auth via fd, skopeo needs to re-open /proc/self/fd/N, + // which requires CAP_DAC_READ_SEARCH. Keep this capability when auth is present. + let keep_dac = config.auth_data.is_some(); + let cmd = + crate::isolation::unprivileged_subprocess(bootc_utils::skopeo_bin(), user, keep_dac); config.skopeo_cmd = Some(cmd); } Ok(()) diff --git a/crates/ostree-ext/src/isolation.rs b/crates/ostree-ext/src/isolation.rs index d96cbfedd..a5c66cdf2 100644 --- a/crates/ostree-ext/src/isolation.rs +++ b/crates/ostree-ext/src/isolation.rs @@ -19,7 +19,15 @@ pub(crate) fn running_in_systemd() -> bool { /// Return a prepared subprocess configuration that will run as an unprivileged user if possible. /// /// This currently only drops privileges when run under systemd with DynamicUser. -pub(crate) fn unprivileged_subprocess(binary: &str, user: &str) -> Command { +/// +/// If `keep_dac_read_search` is true, the CAP_DAC_READ_SEARCH capability is retained. +/// This is needed when passing file descriptors via /proc/self/fd that the subprocess +/// needs to re-open (e.g., auth files for skopeo). +pub(crate) fn unprivileged_subprocess( + binary: &str, + user: &str, + keep_dac_read_search: bool, +) -> Command { // TODO: if we detect we're running in a container as uid 0, perhaps at least switch to the // "bin" user if we can? if !running_in_systemd() { @@ -31,13 +39,21 @@ pub(crate) fn unprivileged_subprocess(binary: &str, user: &str) -> Command { cmd.env_remove("HOME"); cmd.env_remove("XDG_DATA_DIR"); cmd.env_remove("USER"); + + // Determine which capabilities to keep + let cap_set = if keep_dac_read_search { + "-all,+dac_read_search" + } else { + "-all" + }; + cmd.args([ "--no-new-privs", "--init-groups", "--reuid", user, "--bounding-set", - "-all", + cap_set, "--pdeathsig", "TERM", "--",