|
9 | 9 | //! At the current time, this is only used for Logically Bound Images. |
10 | 10 |
|
11 | 11 | use std::collections::HashSet; |
12 | | -use std::io::Seek; |
| 12 | +use std::io::{Seek, Write}; |
13 | 13 | use std::os::unix::process::CommandExt; |
14 | 14 | use std::process::{Command, Stdio}; |
15 | 15 | use std::sync::Arc; |
16 | 16 |
|
17 | 17 | use anyhow::{Context, Result}; |
18 | 18 | use bootc_utils::{AsyncCommandRunExt, CommandRunExt, ExitStatusExt}; |
19 | 19 | use camino::{Utf8Path, Utf8PathBuf}; |
20 | | -use cap_std_ext::cap_std; |
21 | 20 | use cap_std_ext::cap_std::fs::Dir; |
22 | 21 | use cap_std_ext::cap_tempfile::TempDir; |
23 | 22 | use cap_std_ext::cmdext::CapStdExtCommandExt; |
24 | 23 | use cap_std_ext::dirext::CapStdExtDirExt; |
| 24 | +use cap_std_ext::{cap_std, cap_tempfile}; |
25 | 25 | use fn_error_context::context; |
26 | 26 | use ostree_ext::ostree::{self}; |
27 | | -use std::os::fd::{AsRawFd, OwnedFd}; |
| 27 | +use std::os::fd::{AsFd, AsRawFd, OwnedFd}; |
28 | 28 | use tokio::process::Command as AsyncCommand; |
29 | 29 |
|
30 | 30 | // Pass only 100 args at a time just to avoid potentially overflowing argument |
@@ -119,11 +119,38 @@ fn bind_storage_roots(cmd: &mut Command, storage_root: &Dir, run_root: &Dir) -> |
119 | 119 | Ok(()) |
120 | 120 | } |
121 | 121 |
|
122 | | -fn new_podman_cmd_in(storage_root: &Dir, run_root: &Dir) -> Result<Command> { |
| 122 | +// Initialize a `podman` subprocess with: |
| 123 | +// - storage overridden to point to to storage_root |
| 124 | +// - Authentication (auth.json) using the bootc/ostree owned auth |
| 125 | +fn new_podman_cmd_in(sysroot: &Dir, storage_root: &Dir, run_root: &Dir) -> Result<Command> { |
123 | 126 | let mut cmd = Command::new("podman"); |
124 | 127 | bind_storage_roots(&mut cmd, storage_root, run_root)?; |
125 | 128 | let run_root = format!("/proc/self/fd/{STORAGE_RUN_FD}"); |
126 | 129 | cmd.args(["--root", STORAGE_ALIAS_DIR, "--runroot", run_root.as_str()]); |
| 130 | + |
| 131 | + let tmpd = &cap_std::fs::Dir::open_ambient_dir("/tmp", cap_std::ambient_authority())?; |
| 132 | + let mut tempfile = cap_tempfile::TempFile::new_anonymous(tmpd).map(std::io::BufWriter::new)?; |
| 133 | + |
| 134 | + // Keep this in sync with https://github.com/bootc-dev/containers-image-proxy-rs/blob/b5e0861ad5065f47eaf9cda0d48da3529cc1bc43/src/imageproxy.rs#L310 |
| 135 | + // We always override the auth to match the bootc setup. |
| 136 | + let authfile_fd = ostree_ext::globals::get_global_authfile(sysroot)?.map(|v| v.1); |
| 137 | + if let Some(mut fd) = authfile_fd { |
| 138 | + std::io::copy(&mut fd, &mut tempfile)?; |
| 139 | + } else { |
| 140 | + // Note that if there's no bootc-owned auth, then we force an empty authfile to ensure |
| 141 | + // that podman doesn't fall back to searching the user-owned paths. |
| 142 | + tempfile.write_all(b"{}")?; |
| 143 | + } |
| 144 | + |
| 145 | + let tempfile = tempfile |
| 146 | + .into_inner() |
| 147 | + .map_err(|e| e.into_error())? |
| 148 | + .into_std(); |
| 149 | + let fd: Arc<OwnedFd> = std::sync::Arc::new(tempfile.into()); |
| 150 | + let target_fd = fd.as_fd().as_raw_fd(); |
| 151 | + cmd.take_fd_n(fd, target_fd); |
| 152 | + cmd.env("REGISTRY_AUTH_FILE", format!("/proc/self/fd/{target_fd}")); |
| 153 | + |
127 | 154 | Ok(cmd) |
128 | 155 | } |
129 | 156 |
|
@@ -167,7 +194,7 @@ impl CStorage { |
167 | 194 | /// Create a `podman image` Command instance prepared to operate on our alternative |
168 | 195 | /// root. |
169 | 196 | pub(crate) fn new_image_cmd(&self) -> Result<Command> { |
170 | | - let mut r = new_podman_cmd_in(&self.storage_root, &self.run)?; |
| 197 | + let mut r = new_podman_cmd_in(&self.sysroot, &self.storage_root, &self.run)?; |
171 | 198 | // We want to limit things to only manipulating images by default. |
172 | 199 | r.arg("image"); |
173 | 200 | Ok(r) |
@@ -233,7 +260,7 @@ impl CStorage { |
233 | 260 | // There's no explicit API to initialize a containers-storage: |
234 | 261 | // root, simply passing a path will attempt to auto-create it. |
235 | 262 | // We run "podman images" in the new root. |
236 | | - new_podman_cmd_in(&storage_root, &run)? |
| 263 | + new_podman_cmd_in(&sysroot, &storage_root, &run)? |
237 | 264 | .stdout(Stdio::null()) |
238 | 265 | .arg("images") |
239 | 266 | .run_capture_stderr() |
@@ -353,16 +380,6 @@ impl CStorage { |
353 | 380 | cmd.stdin(Stdio::null()); |
354 | 381 | cmd.stdout(Stdio::null()); |
355 | 382 | cmd.args(["pull", image]); |
356 | | - let authfile_fd = |
357 | | - ostree_ext::globals::get_global_authfile(&self.sysroot)?.map(|(_authfile, fd)| fd); |
358 | | - if let Some(fd) = authfile_fd { |
359 | | - let authfile_path = std::fs::read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())) |
360 | | - .map_err(Into::into) |
361 | | - .and_then(|p| { |
362 | | - Utf8PathBuf::from_path_buf(p).map_err(|_| anyhow::anyhow!("Invalid UTF-8")) |
363 | | - })?; |
364 | | - cmd.args(["--authfile", authfile_path.as_str()]); |
365 | | - } |
366 | 383 | tracing::debug!("Pulling image: {image}"); |
367 | 384 | let mut cmd = AsyncCommand::from(cmd); |
368 | 385 | cmd.run().await.context("Failed to pull image")?; |
|
0 commit comments