Skip to content

Commit 86c5419

Browse files
authored
Merge pull request #84 from cgwalters/test-install-t
install: Fall back to `setenforce 0` if needed
2 parents a581429 + 600c64d commit 86c5419

File tree

2 files changed

+49
-9
lines changed

2 files changed

+49
-9
lines changed

lib/src/install.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ pub(crate) struct State {
178178
pub(crate) source: SourceInfo,
179179
/// Force SELinux off in target system
180180
pub(crate) override_disable_selinux: bool,
181+
#[allow(dead_code)]
182+
pub(crate) setenforce_guard: Option<crate::lsm::SetEnforceGuard>,
181183
pub(crate) config_opts: InstallConfigOpts,
182184
pub(crate) target_opts: InstallTargetOpts,
183185
pub(crate) install_config: config::InstallConfiguration,
@@ -609,9 +611,10 @@ impl RootSetup {
609611
pub(crate) fn reexecute_self_for_selinux_if_needed(
610612
srcdata: &SourceInfo,
611613
override_disable_selinux: bool,
612-
) -> Result<bool> {
614+
) -> Result<(bool, Option<crate::lsm::SetEnforceGuard>)> {
613615
let mut ret_did_override = false;
614616
// If the target state has SELinux enabled, we need to check the host state.
617+
let mut g = None;
615618
if srcdata.selinux {
616619
let host_selinux = crate::lsm::selinux_enabled()?;
617620
tracing::debug!("Target has SELinux, host={host_selinux}");
@@ -623,7 +626,7 @@ pub(crate) fn reexecute_self_for_selinux_if_needed(
623626
// so let's just fall through to that.
624627
crate::lsm::container_setup_selinux()?;
625628
// This will re-execute the current process (once).
626-
crate::lsm::selinux_ensure_install()?;
629+
g = crate::lsm::selinux_ensure_install_or_setenforce()?;
627630
} else if override_disable_selinux {
628631
ret_did_override = true;
629632
println!("notice: Target has SELinux enabled, overriding to disable")
@@ -635,7 +638,7 @@ pub(crate) fn reexecute_self_for_selinux_if_needed(
635638
} else {
636639
tracing::debug!("Target does not enable SELinux");
637640
}
638-
Ok(ret_did_override)
641+
Ok((ret_did_override, g))
639642
}
640643

641644
/// Trim, flush outstanding writes, and freeze/thaw the target mounted filesystem;
@@ -744,7 +747,7 @@ async fn prepare_install(
744747
}
745748

746749
// Now, deal with SELinux state.
747-
let override_disable_selinux =
750+
let (override_disable_selinux, setenforce_guard) =
748751
reexecute_self_for_selinux_if_needed(&source, config_opts.disable_selinux)?;
749752

750753
let install_config = config::load_config()?;
@@ -754,6 +757,7 @@ async fn prepare_install(
754757
// combines our command line options along with some bind mounts from the host.
755758
let state = Arc::new(State {
756759
override_disable_selinux,
760+
setenforce_guard,
757761
source,
758762
config_opts,
759763
target_opts,

lib/src/lsm.rs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::fs::File;
1+
#[cfg(feature = "install")]
22
use std::io::Write;
33
use std::os::unix::process::CommandExt;
44
use std::path::Path;
@@ -31,6 +31,9 @@ pub(crate) fn selinux_enabled() -> Result<bool> {
3131
#[context("Ensuring selinux install_t type")]
3232
pub(crate) fn selinux_ensure_install() -> Result<()> {
3333
let guardenv = "_bootc_selinuxfs_mounted";
34+
let current = std::fs::read_to_string("/proc/self/attr/current")
35+
.context("Reading /proc/self/attr/current")?;
36+
tracing::debug!("Current security context is {current}");
3437
if let Some(p) = std::env::var_os(guardenv) {
3538
let p = Path::new(&p);
3639
if p.exists() {
@@ -59,10 +62,42 @@ pub(crate) fn selinux_ensure_install() -> Result<()> {
5962
let mut cmd = Command::new(&tmpf);
6063
cmd.env(guardenv, tmpf);
6164
cmd.args(std::env::args_os().skip(1));
62-
tracing::debug!("Re-executing");
65+
tracing::debug!("Re-executing {cmd:?}");
6366
Err(anyhow::Error::msg(cmd.exec()).context("execve"))
6467
}
6568

69+
/// A type which will reset SELinux back to enforcing mode when dropped.
70+
/// This is a workaround for the deep difficulties in trying to reliably
71+
/// gain the `mac_admin` permission (install_t).
72+
#[cfg(feature = "install")]
73+
#[must_use]
74+
pub(crate) struct SetEnforceGuard;
75+
76+
#[cfg(feature = "install")]
77+
impl Drop for SetEnforceGuard {
78+
fn drop(&mut self) {
79+
let _ = selinux_set_permissive(false);
80+
}
81+
}
82+
83+
/// Try to enter the install_t domain, but if we can't do that, then
84+
/// just setenforce 0.
85+
#[context("Ensuring selinux install_t type")]
86+
#[cfg(feature = "install")]
87+
pub(crate) fn selinux_ensure_install_or_setenforce() -> Result<Option<SetEnforceGuard>> {
88+
selinux_ensure_install()?;
89+
let current = std::fs::read_to_string("/proc/self/attr/current")
90+
.context("Reading /proc/self/attr/current")?;
91+
let g = if !current.contains("install_t") {
92+
tracing::warn!("Failed to enter install_t; temporarily setting permissive mode");
93+
selinux_set_permissive(true)?;
94+
Some(SetEnforceGuard)
95+
} else {
96+
None
97+
};
98+
Ok(g)
99+
}
100+
66101
/// Ensure that /sys/fs/selinux is mounted, and ensure we're running
67102
/// as install_t.
68103
#[context("Ensuring selinux mount")]
@@ -84,13 +119,13 @@ pub(crate) fn container_setup_selinux() -> Result<()> {
84119
#[context("Setting SELinux permissive mode")]
85120
#[allow(dead_code)]
86121
#[cfg(feature = "install")]
87-
pub(crate) fn selinux_set_permissive() -> Result<()> {
122+
pub(crate) fn selinux_set_permissive(permissive: bool) -> Result<()> {
88123
let enforce_path = &Utf8Path::new(SELINUXFS).join("enforce");
89124
if !enforce_path.exists() {
90125
return Ok(());
91126
}
92-
let mut f = File::open(enforce_path)?;
93-
f.write_all(b"0")?;
127+
let mut f = std::fs::File::options().write(true).open(enforce_path)?;
128+
f.write_all(if permissive { b"0" } else { b"1" })?;
94129
tracing::debug!("Set SELinux permissive mode");
95130
Ok(())
96131
}
@@ -111,6 +146,7 @@ fn selinux_label_for_path(target: &str) -> Result<String> {
111146
#[context("Labeling {as_path}")]
112147
pub(crate) fn lsm_label(target: &Utf8Path, as_path: &Utf8Path, recurse: bool) -> Result<()> {
113148
let label = selinux_label_for_path(as_path.as_str())?;
149+
tracing::debug!("Label for {target} is {label}");
114150
let st = Command::new("chcon")
115151
.arg("-h")
116152
.args(recurse.then_some("-R"))

0 commit comments

Comments
 (0)