Skip to content

Commit 8472970

Browse files
authored
Merge pull request #69 from cgwalters/reexec-prep
install: A few cleanups
2 parents 652771d + 9f1064b commit 8472970

File tree

1 file changed

+78
-62
lines changed

1 file changed

+78
-62
lines changed

lib/src/install.rs

Lines changed: 78 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use ostree_ext::prelude::Cast;
3131
use serde::{Deserialize, Serialize};
3232

3333
use self::baseline::InstallBlockDeviceOpts;
34+
use crate::containerenv::ContainerExecutionInfo;
3435
use crate::lsm::lsm_label;
3536
use crate::task::Task;
3637
use crate::utils::run_in_host_mountns;
@@ -158,17 +159,28 @@ pub(crate) struct InstallToFilesystemOpts {
158159
pub(crate) config_opts: InstallConfigOpts,
159160
}
160161

161-
// Shared read-only global state
162-
pub(crate) struct State {
162+
/// Global state captured from the container.
163+
#[derive(Debug, Clone)]
164+
pub(crate) struct SourceInfo {
163165
/// Image reference we'll pull from (today always containers-storage: type)
164-
source_imageref: ostree_container::ImageReference,
166+
pub(crate) imageref: ostree_container::ImageReference,
165167
/// The digest to use for pulls
166-
source_digest: String,
168+
pub(crate) digest: String,
169+
/// The embedded base OSTree commit checksum
170+
#[allow(dead_code)]
171+
pub(crate) commit: String,
172+
/// Whether or not SELinux appears to be enabled in the source commit
173+
pub(crate) selinux: bool,
174+
}
175+
176+
// Shared read-only global state
177+
pub(crate) struct State {
178+
pub(crate) source: SourceInfo,
167179
/// Force SELinux off in target system
168-
override_disable_selinux: bool,
169-
config_opts: InstallConfigOpts,
170-
target_opts: InstallTargetOpts,
171-
install_config: config::InstallConfiguration,
180+
pub(crate) override_disable_selinux: bool,
181+
pub(crate) config_opts: InstallConfigOpts,
182+
pub(crate) target_opts: InstallTargetOpts,
183+
pub(crate) install_config: config::InstallConfiguration,
172184
}
173185

174186
/// Path to initially deployed version information
@@ -261,6 +273,45 @@ impl FromStr for MountSpec {
261273
}
262274
}
263275

276+
impl SourceInfo {
277+
// Inspect container information and convert it to an ostree image reference
278+
// that pulls from containers-storage.
279+
#[context("Gathering source info from container env")]
280+
pub(crate) fn from_container(container_info: &ContainerExecutionInfo) -> Result<Self> {
281+
if !container_info.engine.starts_with("podman") {
282+
anyhow::bail!("Currently this command only supports being executed via podman");
283+
}
284+
if container_info.imageid.is_empty() {
285+
anyhow::bail!("Invalid empty imageid");
286+
}
287+
let imageref = ostree_container::ImageReference {
288+
transport: ostree_container::Transport::ContainerStorage,
289+
name: container_info.image.clone(),
290+
};
291+
let digest = crate::podman::imageid_to_digest(&container_info.imageid)?;
292+
let cancellable = ostree::gio::Cancellable::NONE;
293+
let commit = Task::new("Reading ostree commit", "ostree")
294+
.args(["--repo=/ostree/repo", "rev-parse", "--single"])
295+
.quiet()
296+
.read()?;
297+
let root = cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
298+
let repo = ostree::Repo::open_at_dir(&root, "ostree/repo")?;
299+
let root = repo
300+
.read_commit(commit.trim(), cancellable)
301+
.context("Reading commit")?
302+
.0;
303+
let root = root.downcast_ref::<ostree::RepoFile>().unwrap();
304+
let xattrs = root.xattrs(cancellable)?;
305+
let selinux = crate::lsm::xattrs_have_selinux(&xattrs);
306+
Ok(Self {
307+
imageref,
308+
digest,
309+
commit,
310+
selinux,
311+
})
312+
}
313+
}
314+
264315
mod config {
265316
use super::*;
266317

@@ -379,7 +430,7 @@ async fn initialize_ostree_root_from_self(
379430
} else {
380431
ostree_container::OstreeImageReference {
381432
sigverify: target_sigverify,
382-
imgref: state.source_imageref.clone(),
433+
imgref: state.source.imageref.clone(),
383434
}
384435
};
385436

@@ -420,15 +471,15 @@ async fn initialize_ostree_root_from_self(
420471
let src_imageref = if skopeo_supports_containers_storage()? {
421472
// We always use exactly the digest of the running image to ensure predictability.
422473
let spec =
423-
crate::utils::digested_pullspec(&state.source_imageref.name, &state.source_digest);
474+
crate::utils::digested_pullspec(&state.source.imageref.name, &state.source.digest);
424475
ostree_container::ImageReference {
425476
transport: ostree_container::Transport::ContainerStorage,
426477
name: spec,
427478
}
428479
} else {
429480
let td = tempfile::tempdir_in("/var/tmp")?;
430481
let path: &Utf8Path = td.path().try_into().unwrap();
431-
let r = copy_to_oci(&state.source_imageref, path)?;
482+
let r = copy_to_oci(&state.source.imageref, path)?;
432483
temporary_dir = Some(td);
433484
r
434485
};
@@ -562,39 +613,12 @@ impl RootSetup {
562613
}
563614
}
564615

565-
pub(crate) struct SourceData {
566-
/// The embedded base OSTree commit checksum
567-
#[allow(dead_code)]
568-
pub(crate) commit: String,
569-
/// Whether or not SELinux appears to be enabled in the source commit
570-
pub(crate) selinux: bool,
571-
}
572-
573-
#[context("Gathering source data")]
574-
fn gather_source_data() -> Result<SourceData> {
575-
let cancellable = ostree::gio::Cancellable::NONE;
576-
let commit = Task::new("Reading ostree commit", "ostree")
577-
.args(["--repo=/ostree/repo", "rev-parse", "--single"])
578-
.quiet()
579-
.read()?;
580-
let root = cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
581-
let repo = ostree::Repo::open_at_dir(&root, "ostree/repo")?;
582-
let root = repo
583-
.read_commit(commit.trim(), cancellable)
584-
.context("Reading commit")?
585-
.0;
586-
let root = root.downcast_ref::<ostree::RepoFile>().unwrap();
587-
let xattrs = root.xattrs(cancellable)?;
588-
let selinux = crate::lsm::xattrs_have_selinux(&xattrs);
589-
Ok(SourceData { commit, selinux })
590-
}
591-
592616
/// If we detect that the target ostree commit has SELinux labels,
593617
/// and we aren't passed an override to disable it, then ensure
594618
/// the running process is labeled with install_t so it can
595619
/// write arbitrary labels.
596620
pub(crate) fn reexecute_self_for_selinux_if_needed(
597-
srcdata: &SourceData,
621+
srcdata: &SourceInfo,
598622
override_disable_selinux: bool,
599623
) -> Result<bool> {
600624
let mut ret_did_override = false;
@@ -646,13 +670,7 @@ pub(crate) fn finalize_filesystem(fs: &Utf8Path) -> Result<()> {
646670
Ok(())
647671
}
648672

649-
/// Preparation for an install; validates and prepares some (thereafter immutable) global state.
650-
async fn prepare_install(
651-
config_opts: InstallConfigOpts,
652-
target_opts: InstallTargetOpts,
653-
) -> Result<Arc<State>> {
654-
// We need full root privileges, i.e. --privileged in podman
655-
crate::cli::require_root()?;
673+
fn require_systemd_pid1() -> Result<()> {
656674
// We require --pid=host
657675
let pid = std::fs::read_link("/proc/1/exe").context("reading /proc/1/exe")?;
658676
let pid = pid
@@ -661,21 +679,21 @@ async fn prepare_install(
661679
if !pid.contains("systemd") {
662680
anyhow::bail!("This command must be run with --pid=host")
663681
}
682+
Ok(())
683+
}
684+
685+
/// Preparation for an install; validates and prepares some (thereafter immutable) global state.
686+
async fn prepare_install(
687+
config_opts: InstallConfigOpts,
688+
target_opts: InstallTargetOpts,
689+
) -> Result<Arc<State>> {
690+
// We need full root privileges, i.e. --privileged in podman
691+
crate::cli::require_root()?;
692+
require_systemd_pid1()?;
664693

665694
// This command currently *must* be run inside a privileged container.
666695
let container_info = crate::containerenv::get_container_execution_info()?;
667-
if !container_info.engine.starts_with("podman") {
668-
anyhow::bail!("Currently this command only supports being executed via podman");
669-
}
670-
if container_info.imageid.is_empty() {
671-
anyhow::bail!("Invalid empty imageid");
672-
}
673-
let source_imageref = ostree_container::ImageReference {
674-
transport: ostree_container::Transport::ContainerStorage,
675-
name: container_info.image.clone(),
676-
};
677-
// Find the exact digested image we are running
678-
let source_digest = crate::podman::imageid_to_digest(&container_info.imageid)?;
696+
let source = SourceInfo::from_container(&container_info)?;
679697

680698
// Even though we require running in a container, the mounts we create should be specific
681699
// to this process, so let's enter a private mountns to avoid leaking them.
@@ -693,9 +711,8 @@ async fn prepare_install(
693711
}
694712

695713
// Now, deal with SELinux state.
696-
let srcdata = gather_source_data()?;
697714
let override_disable_selinux =
698-
reexecute_self_for_selinux_if_needed(&srcdata, config_opts.disable_selinux)?;
715+
reexecute_self_for_selinux_if_needed(&source, config_opts.disable_selinux)?;
699716

700717
let install_config = config::load_config()?;
701718

@@ -706,8 +723,7 @@ async fn prepare_install(
706723
bind_mount_from_host("/var/tmp", "/var/tmp")?;
707724
let state = Arc::new(State {
708725
override_disable_selinux,
709-
source_imageref,
710-
source_digest,
726+
source,
711727
config_opts,
712728
target_opts,
713729
install_config,

0 commit comments

Comments
 (0)