Skip to content

Commit 770289f

Browse files
committed
Soft reboot: Detect SELinux policy deltas
Add check to prevent soft reboot when SELinux policies differ between booted and target deployments, since policy is not reloaded across soft reboots. Assisted-by: Cursor (Auto) Signed-off-by: gursewak1997 <[email protected]>
1 parent 71dc8e5 commit 770289f

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

crates/lib/src/cli.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,51 @@ fn has_soft_reboot_capability(deployment: Option<&crate::spec::BootEntry>) -> bo
763763
deployment.map(|d| d.soft_reboot_capable).unwrap_or(false)
764764
}
765765

766+
/// Check if SELinux policy differs between booted and target deployments.
767+
/// Returns an error if SELinux is enabled and the policies differ.
768+
#[context("Checking SELinux policy compatibility with soft reboot")]
769+
fn check_selinux_policy_for_soft_reboot(
770+
sysroot: &SysrootLock,
771+
booted_deployment: &ostree::Deployment,
772+
target_deployment: &ostree::Deployment,
773+
) -> Result<()> {
774+
// Only check if SELinux is enabled
775+
if !crate::lsm::selinux_enabled()? {
776+
return Ok(());
777+
}
778+
779+
let booted_fd = crate::utils::deployment_fd(sysroot, booted_deployment)?;
780+
let booted_policy = crate::lsm::new_sepolicy_at(&booted_fd)?;
781+
let target_fd = crate::utils::deployment_fd(sysroot, target_deployment)?;
782+
let target_policy = crate::lsm::new_sepolicy_at(&target_fd)?;
783+
784+
match (booted_policy, target_policy) {
785+
(None, None) => Ok(()), // Both absent, allow soft reboot
786+
(Some(_), None) | (None, Some(_)) => {
787+
anyhow::bail!(
788+
"SELinux policy presence differs between booted and target deployments. \
789+
Soft reboot cannot be used because SELinux policy is not reloaded across soft reboots. \
790+
Please use a full reboot instead."
791+
)
792+
}
793+
(Some(booted), Some(target)) => {
794+
// SAFETY: new_sepolicy_at filters out policies without checksums
795+
let booted_csum = booted.csum().expect("booted policy should have checksum");
796+
let target_csum = target.csum().expect("target policy should have checksum");
797+
if booted_csum != target_csum {
798+
anyhow::bail!(
799+
"SELinux policy differs between booted and target deployments (booted: {:?}, target: {:?}). \
800+
Soft reboot cannot be used because SELinux policy is not reloaded across soft reboots. \
801+
Please use a full reboot instead.",
802+
booted_csum,
803+
target_csum
804+
)
805+
}
806+
Ok(())
807+
}
808+
}
809+
}
810+
766811
/// Prepare a soft reboot for the given deployment
767812
#[context("Preparing soft reboot")]
768813
fn prepare_soft_reboot(sysroot: &SysrootLock, deployment: &ostree::Deployment) -> Result<()> {
@@ -835,6 +880,11 @@ fn soft_reboot_staged(sysroot: &SysrootLock) -> Result<()> {
835880
.find(|d| d.is_staged())
836881
.ok_or_else(|| anyhow::anyhow!("Failed to find staged deployment"))?;
837882

883+
// Check SELinux policy compatibility before allowing soft reboot
884+
if let Some(booted_deployment) = sysroot.booted_deployment() {
885+
check_selinux_policy_for_soft_reboot(sysroot, &booted_deployment, staged_deployment)?;
886+
}
887+
838888
prepare_soft_reboot(sysroot, staged_deployment)?;
839889
Ok(())
840890
}
@@ -849,6 +899,13 @@ fn soft_reboot_rollback(booted_ostree: &BootedOstree<'_>) -> Result<()> {
849899
.first()
850900
.ok_or_else(|| anyhow::anyhow!("No rollback deployment found!"))?;
851901

902+
// Check SELinux policy compatibility before allowing soft reboot
903+
check_selinux_policy_for_soft_reboot(
904+
booted_ostree.sysroot,
905+
&booted_ostree.deployment,
906+
target_deployment,
907+
)?;
908+
852909
prepare_soft_reboot(booted_ostree.sysroot, target_deployment)
853910
}
854911

0 commit comments

Comments
 (0)