From f707f77d305bf6d4717339d8ff686266fb4ba5c6 Mon Sep 17 00:00:00 2001
From: "Brad P. Crochet" <brad@redhat.com>
Date: Tue, 13 Feb 2024 09:49:59 -0500
Subject: [PATCH] Add selinuxfs to be mounted in the container

As a follow-on to #302, we want to also mount the selinuxfs special
filesystem if the host also has that filesystem mounted.

Related #303

Signed-off-by: Brad P. Crochet <brad@redhat.com>
---
 lib/src/install.rs | 43 +++++++++++++++++++++----------------------
 lib/src/lsm.rs     | 18 ------------------
 2 files changed, 21 insertions(+), 40 deletions(-)

diff --git a/lib/src/install.rs b/lib/src/install.rs
index 4f04246d7..ea56c27df 100644
--- a/lib/src/install.rs
+++ b/lib/src/install.rs
@@ -51,6 +51,12 @@ const BOOT: &str = "boot";
 const RUN_BOOTC: &str = "/run/bootc";
 /// This is an ext4 special directory we need to ignore.
 const LOST_AND_FOUND: &str = "lost+found";
+/// The mount path for selinux
+#[cfg(feature = "install")]
+const SELINUXFS: &str = "/sys/fs/selinux";
+/// The mount path for uefi
+#[cfg(feature = "install")]
+const EFIVARFS: &str = "/sys/firmware/efi/efivars";
 pub(crate) const ARCH_USES_EFI: bool = cfg!(any(target_arch = "x86_64", target_arch = "aarch64"));
 
 /// Kernel argument used to specify we want the rootfs mounted read-write by default
@@ -750,7 +756,7 @@ pub(crate) fn reexecute_self_for_selinux_if_needed(
             // already queried by something else (e.g. glib's constructor), we would also need
             // to re-exec.  But, selinux_ensure_install does that unconditionally right now too,
             // so let's just fall through to that.
-            crate::lsm::container_setup_selinux()?;
+            setup_sys_mount("selinuxfs", SELINUXFS)?;
             // This will re-execute the current process (once).
             g = crate::lsm::selinux_ensure_install_or_setenforce()?;
         } else if std::env::var_os(skip_check_envvar).is_some() {
@@ -871,39 +877,32 @@ pub(crate) fn setup_tmp_mounts() -> Result<()> {
 
 /// By default, podman/docker etc. when passed `--privileged` mount `/sys` as read-only,
 /// but non-recursively.  We selectively grab sub-filesystems that we need.
-#[context("Ensuring sys mounts")]
-pub(crate) fn setup_sys_mounts() -> Result<()> {
+#[context("Ensuring sys mount {fspath} {fstype}")]
+pub(crate) fn setup_sys_mount(fstype: &str, fspath: &str) -> Result<()> {
     tracing::debug!("Setting up sys mounts");
-
-    let root_efivars = "/sys/firmware/efi/efivars";
-    let efivars = format!("/proc/1/root/{root_efivars}");
-    // Does efivars even exist in the host? If not, we are
-    // not dealing with an EFI system
-    if !Path::new(efivars.as_str()).try_exists()? {
+    let rootfs = format!("/proc/1/root/{fspath}");
+    // Does mount point even exist in the host?
+    if !Path::new(rootfs.as_str()).try_exists()? {
         return Ok(());
     }
 
     // Now, let's find out if it's populated
-    if std::fs::read_dir(efivars)?.next().is_none() {
+    if std::fs::read_dir(rootfs)?.next().is_none() {
         return Ok(());
     }
 
-    // First of all, does the container already have the mount?
-    let path = Utf8Path::new(root_efivars);
-    if path.try_exists()? {
-        tracing::debug!("Check if efivarfs already mount");
-        let inspect = crate::mount::inspect_filesystem(path);
-        if inspect.is_ok() {
-            tracing::trace!("Already have efivarfs {root_efivars}");
-            return Ok(());
-        }
+    // Check that the path that should be mounted is even populated.
+    // Since we are dealing with /sys mounts here, if it's populated,
+    // we can be at least a little certain that it's mounted.
+    if Path::new(fspath).try_exists()? && std::fs::read_dir(fspath)?.next().is_some() {
+        return Ok(());
     }
 
     // This means the host has this mounted, so we should mount it too
     Task::new_and_run(
-        "Mounting efivarfs /sys/firmware/efi/efivars",
+        format!("Mounting {fstype} {fspath}"),
         "mount",
-        ["-t", "efivarfs", "efivars", "/sys/firmware/efi/efivars"],
+        ["-t", fstype, fstype, fspath],
     )
 }
 
@@ -1002,7 +1001,7 @@ async fn prepare_install(
         super::cli::ensure_self_unshared_mount_namespace().await?;
     }
 
-    setup_sys_mounts()?;
+    setup_sys_mount("efivarfs", EFIVARFS)?;
 
     // Now, deal with SELinux state.
     let (override_disable_selinux, setenforce_guard) =
diff --git a/lib/src/lsm.rs b/lib/src/lsm.rs
index e6bf5ed41..9b9ae1424 100644
--- a/lib/src/lsm.rs
+++ b/lib/src/lsm.rs
@@ -121,24 +121,6 @@ pub(crate) fn selinux_ensure_install_or_setenforce() -> Result<Option<SetEnforce
     Ok(g)
 }
 
-/// Ensure that /sys/fs/selinux is mounted, and ensure we're running
-/// as install_t.
-#[context("Ensuring selinux mount")]
-#[cfg(feature = "install")]
-pub(crate) fn container_setup_selinux() -> Result<()> {
-    let path = Utf8Path::new(SELINUXFS);
-    if !path.join("enforce").exists() {
-        if !path.exists() {
-            tracing::debug!("Creating {path}");
-            std::fs::create_dir(path)?;
-        }
-        Task::new("Mounting selinuxfs", "mount")
-            .args(["selinuxfs", "-t", "selinuxfs", path.as_str()])
-            .run()?;
-    }
-    Ok(())
-}
-
 #[context("Setting SELinux permissive mode")]
 #[allow(dead_code)]
 #[cfg(feature = "install")]