Skip to content

Commit cbe6062

Browse files
authored
Merge pull request #284 from cgwalters/more-install-t
Fix install_t again
2 parents c3b5fc8 + f2d5949 commit cbe6062

File tree

3 files changed

+40
-20
lines changed

3 files changed

+40
-20
lines changed

lib/src/cli.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,9 @@ pub(crate) async fn prepare_for_write() -> Result<()> {
293293
}
294294
ensure_self_unshared_mount_namespace().await?;
295295
if crate::lsm::selinux_enabled()? {
296-
crate::lsm::selinux_ensure_install()?;
296+
if !crate::lsm::selinux_ensure_install()? {
297+
tracing::warn!("Do not have install_t capabilities");
298+
}
297299
}
298300
Ok(())
299301
}

lib/src/install.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -873,9 +873,22 @@ fn ensure_var() -> Result<()> {
873873
/// We can't bind mount though - we need to symlink it so that each calling process
874874
/// will traverse the link.
875875
#[context("Linking tmp mounts to host")]
876-
pub(crate) fn propagate_tmp_mounts_to_host() -> Result<()> {
877-
// Point our /tmp and /var/tmp at the host, via the /proc/1/root magic link
878-
for path in ["/tmp", "/var/tmp"].map(Utf8Path::new) {
876+
pub(crate) fn setup_tmp_mounts() -> Result<()> {
877+
let st = rustix::fs::statfs("/tmp")?;
878+
if st.f_type == libc::TMPFS_MAGIC {
879+
tracing::trace!("Already have tmpfs /tmp")
880+
} else {
881+
// Note we explicitly also don't want a "nosuid" tmp, because that
882+
// suppresses our install_t transition
883+
Task::new_and_run(
884+
"Mounting tmpfs /tmp",
885+
"mount",
886+
["tmpfs", "-t", "tmpfs", "/tmp"],
887+
)?;
888+
}
889+
890+
// Point our /var/tmp at the host, via the /proc/1/root magic link
891+
for path in ["/var/tmp"].map(Utf8Path::new) {
879892
if path.try_exists()? {
880893
let st = rustix::fs::statfs(path.as_std_path()).context(path)?;
881894
if st.f_type != libc::OVERLAYFS_SUPER_MAGIC {
@@ -999,7 +1012,7 @@ async fn prepare_install(
9991012
}
10001013

10011014
ensure_var()?;
1002-
propagate_tmp_mounts_to_host()?;
1015+
setup_tmp_mounts()?;
10031016

10041017
// Even though we require running in a container, the mounts we create should be specific
10051018
// to this process, so let's enter a private mountns to avoid leaking them.

lib/src/lsm.rs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,18 @@ fn get_current_security_context() -> Result<String> {
3333
std::fs::read_to_string(SELF_CURRENT).with_context(|| format!("Reading {SELF_CURRENT}"))
3434
}
3535

36-
/// Determine if a security context is the "install_t" type which can
37-
/// write arbitrary labels.
38-
fn context_is_install_t(context: &str) -> bool {
39-
// TODO: we shouldn't actually hardcode this...it's just ugly though
40-
// to figure out whether we really can gain CAP_MAC_ADMIN.
41-
context.contains(":install_t:")
36+
#[context("Testing install_t")]
37+
fn test_install_t() -> Result<bool> {
38+
let tmpf = tempfile::NamedTempFile::new()?;
39+
let st = Command::new("chcon")
40+
.args(["-t", "invalid_bootcinstall_testlabel_t"])
41+
.arg(tmpf.path())
42+
.status()?;
43+
Ok(st.success())
4244
}
4345

4446
#[context("Ensuring selinux install_t type")]
45-
pub(crate) fn selinux_ensure_install() -> Result<()> {
47+
pub(crate) fn selinux_ensure_install() -> Result<bool> {
4648
let guardenv = "_bootc_selinuxfs_mounted";
4749
let current = get_current_security_context()?;
4850
tracing::debug!("Current security context is {current}");
@@ -54,9 +56,13 @@ pub(crate) fn selinux_ensure_install() -> Result<()> {
5456
} else {
5557
tracing::debug!("Assuming we now have a privileged (e.g. install_t) label");
5658
}
57-
return Ok(());
59+
return test_install_t();
60+
}
61+
if test_install_t()? {
62+
tracing::debug!("We have install_t");
63+
return Ok(true);
5864
}
59-
tracing::debug!("Copying self to temporary file for re-exec");
65+
tracing::debug!("Lacking install_t capabilities; copying self to temporary file for re-exec");
6066
// OK now, we always copy our binary to a tempfile, set its security context
6167
// to match that of /usr/bin/ostree, and then re-exec. This is really a gross
6268
// hack; we can't always rely on https://github.com/fedora-selinux/selinux-policy/pull/1500/commits/67eb283c46d35a722636d749e5b339615fe5e7f5
@@ -98,18 +104,17 @@ impl Drop for SetEnforceGuard {
98104
#[cfg(feature = "install")]
99105
pub(crate) fn selinux_ensure_install_or_setenforce() -> Result<Option<SetEnforceGuard>> {
100106
// If the process already has install_t, exit early
101-
let current = get_current_security_context()?;
102-
if context_is_install_t(&current) {
107+
// Note that this may re-exec the entire process
108+
if selinux_ensure_install()? {
103109
return Ok(None);
104110
}
105-
// Note that this will re-exec the entire process
106-
selinux_ensure_install()?;
107-
let g = if !context_is_install_t(&current) {
111+
let g = if std::env::var_os("BOOTC_SETENFORCE0_FALLBACK").is_some() {
108112
tracing::warn!("Failed to enter install_t; temporarily setting permissive mode");
109113
selinux_set_permissive(true)?;
110114
Some(SetEnforceGuard)
111115
} else {
112-
None
116+
let current = get_current_security_context()?;
117+
anyhow::bail!("Failed to enter install_t (running as {current}) - use BOOTC_SETENFORCE0_FALLBACK=1 to override");
113118
};
114119
Ok(g)
115120
}

0 commit comments

Comments
 (0)