Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lsm: Forcibly relabel all initial state #294

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,4 @@ jobs:
sudo podman run --rm -ti --privileged --env BOOTC_SKIP_SELINUX_HOST_CHECK=1 --env RUST_LOG=debug -v /:/target -v /var/lib/containers:/var/lib/containers -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable \
quay.io/centos-bootc/fedora-bootc-dev:eln bootc install to-filesystem \
--replace=alongside /target
sudo ls -ldZ / /ostree/deploy/default/deploy/* /ostree/deploy/default/deploy/*/etc
sudo ls -ldZ / /boot /ostree/deploy/default /ostree/repo/objects /ostree/deploy/default/deploy/* /ostree/deploy/default/deploy/*/etc
40 changes: 14 additions & 26 deletions lib/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use serde::{Deserialize, Serialize};

use self::baseline::InstallBlockDeviceOpts;
use crate::containerenv::ContainerExecutionInfo;
use crate::lsm::selinux_label_recurse;
use crate::task::Task;
use crate::utils::sigpolicy_from_opts;

Expand Down Expand Up @@ -263,21 +264,6 @@ pub(crate) struct State {
pub(crate) install_config: config::InstallConfiguration,
}

impl State {
// Wraps core lsm labeling functionality, conditionalizing based on source state
pub(crate) fn lsm_label(
&self,
target: &Utf8Path,
as_path: &Utf8Path,
recurse: bool,
) -> Result<()> {
if !self.source.selinux {
return Ok(());
}
crate::lsm::lsm_label(target, as_path, recurse)
}
}

/// Path to initially deployed version information
const BOOTC_ALEPH_PATH: &str = ".bootc-aleph.json";

Expand Down Expand Up @@ -466,9 +452,15 @@ async fn initialize_ostree_root_from_self(
let rootfs = root_setup.rootfs.as_path();
let cancellable = gio::Cancellable::NONE;

// Ensure that the physical root is labeled.
// Another implementation: https://github.com/coreos/coreos-assembler/blob/3cd3307904593b3a131b81567b13a4d0b6fe7c90/src/create_disk.sh#L295
state.lsm_label(rootfs, "/".into(), false)?;
let sepolicy = if state.override_disable_selinux {
None
} else {
let root = ostree::gio::File::for_path("/");
Some(ostree::SePolicy::new(
&root,
ostree::gio::Cancellable::NONE,
)?)
};

// TODO: make configurable?
let stateroot = STATEROOT_DEFAULT;
Expand All @@ -478,12 +470,6 @@ async fn initialize_ostree_root_from_self(
["admin", "init-fs", "--modern", rootfs.as_str()],
)?;

// And also label /boot AKA xbootldr, if it exists
let bootdir = rootfs.join("boot");
if bootdir.try_exists()? {
state.lsm_label(&bootdir, "/boot".into(), false)?;
}

// Default to avoiding grub2-mkconfig etc., but we need to use zipl on s390x.
// TODO: Lower this logic into ostree proper.
let bootloader = if cfg!(target_arch = "s390x") {
Expand All @@ -509,8 +495,10 @@ async fn initialize_ostree_root_from_self(
.cwd(rootfs_dir)?
.run()?;

// Ensure everything in the ostree repo is labeled
state.lsm_label(&rootfs.join("ostree"), "/usr".into(), true)?;
if let Some(policy) = sepolicy.as_ref() {
selinux_label_recurse(policy, &root_setup.rootfs_fd, "./".into())
.context("Labeling physical root")?;
}

let sysroot = ostree::Sysroot::new(Some(&gio::File::for_path(rootfs)));
sysroot.load(cancellable)?;
Expand Down
5 changes: 0 additions & 5 deletions lib/src/install/baseline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,15 +364,10 @@ pub(crate) fn install_create_rootfs(
.collect::<Vec<_>>();

mount::mount(&rootdev, &rootfs)?;
state.lsm_label(&rootfs, "/".into(), false)?;
let rootfs_fd = Dir::open_ambient_dir(&rootfs, cap_std::ambient_authority())?;
let bootfs = rootfs.join("boot");
std::fs::create_dir(&bootfs).context("Creating /boot")?;
// The underlying directory on the root should be labeled
state.lsm_label(&bootfs, "/boot".into(), false)?;
mount::mount(bootdev, &bootfs)?;
// And we want to label the root mount of /boot
state.lsm_label(&bootfs, "/boot".into(), false)?;

// Create the EFI system partition, if applicable
if let Some(esp_partno) = esp_partno {
Expand Down
44 changes: 44 additions & 0 deletions lib/src/lsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ use std::process::Command;

use anyhow::{Context, Result};
use camino::{Utf8Path, Utf8PathBuf};
use cap_std_ext::cap_std::fs::{Dir, MetadataExt};
use fn_error_context::context;
#[cfg(feature = "install")]
use gvariant::{aligned_bytes::TryAsAligned, Marker, Structure};
#[cfg(feature = "install")]
use ostree_ext::ostree;
use rustix::fd::AsRawFd;

use crate::task::Task;

Expand Down Expand Up @@ -168,6 +170,48 @@ fn selinux_label_for_path(target: &str) -> Result<String> {
Ok(label.trim().to_string())
}

fn selinux_set_one_label(
policy: &ostree::SePolicy,
root: &Dir,
path: &Utf8Path,
mode: u32,
) -> Result<()> {
let label = policy.label(path.as_str(), mode, ostree::gio::Cancellable::NONE)?;
if let Some(label) = label {
let selfpath = format!("/proc/self/fd/{}", root.as_raw_fd());
rustix::fs::lsetxattr(
&selfpath,
SELINUX_XATTR,
label.as_bytes(),
rustix::fs::XattrFlags::empty(),
)?;
}
Ok(())
}

pub(crate) fn selinux_label_recurse(
policy: &ostree::SePolicy,
root: &Dir,
path: &Utf8Path,
) -> Result<()> {
let meta = root.symlink_metadata(path)?;
selinux_set_one_label(policy, root, path, meta.mode())?;
if meta.is_dir() {
for ent in root.read_dir(path)? {
let ent = ent?;
let name = ent.file_name();
let name = if let Some(name) = name.to_str() {
name
} else {
anyhow::bail!("Invalid filename: {name:?}");
};
let path = path.join(name);
selinux_label_recurse(policy, root, &path)?;
}
}
Ok(())
}

// Write filesystem labels (currently just for SELinux)
#[context("Labeling {as_path}")]
pub(crate) fn lsm_label(target: &Utf8Path, as_path: &Utf8Path, recurse: bool) -> Result<()> {
Expand Down
Loading