Skip to content

Commit 7001036

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 7001036

File tree

1 file changed

+70
-0
lines changed

1 file changed

+70
-0
lines changed

crates/lib/src/cli.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,64 @@ 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+
// Load SELinux policy from booted deployment
780+
let booted_fd = crate::utils::deployment_fd(sysroot, booted_deployment)?;
781+
let booted_policy = crate::lsm::new_sepolicy_at(&booted_fd)?;
782+
783+
// Load SELinux policy from target deployment
784+
let target_fd = crate::utils::deployment_fd(sysroot, target_deployment)?;
785+
let target_policy = crate::lsm::new_sepolicy_at(&target_fd)?;
786+
787+
// Ensure both deployments have the same policy presence state
788+
// If one has a policy and the other doesn't, soft reboot is unsafe
789+
if booted_policy.is_some() != target_policy.is_some() {
790+
anyhow::bail!(
791+
"SELinux policy presence differs between booted ({}) and target ({}) deployments. \
792+
Soft reboot cannot be used because SELinux policy is not reloaded across soft reboots. \
793+
Please use a full reboot instead.",
794+
if booted_policy.is_some() { "present" } else { "absent" },
795+
if target_policy.is_some() { "present" } else { "absent" }
796+
);
797+
}
798+
799+
// If both deployments have policies, they must match
800+
if let (Some(booted_policy), Some(target_policy)) = (booted_policy, target_policy) {
801+
// Compare policy checksums
802+
// SAFETY: new_sepolicy_at filters out policies without checksums, so these should always be Some
803+
let booted_csum = booted_policy
804+
.csum()
805+
.expect("booted policy should have checksum");
806+
let target_csum = target_policy
807+
.csum()
808+
.expect("target policy should have checksum");
809+
810+
if booted_csum != target_csum {
811+
anyhow::bail!(
812+
"SELinux policy differs between booted and target deployments (booted: {:?}, target: {:?}). \
813+
Soft reboot cannot be used because SELinux policy is not reloaded across soft reboots. \
814+
Please use a full reboot instead.",
815+
booted_csum,
816+
target_csum
817+
);
818+
}
819+
}
820+
821+
Ok(())
822+
}
823+
766824
/// Prepare a soft reboot for the given deployment
767825
#[context("Preparing soft reboot")]
768826
fn prepare_soft_reboot(sysroot: &SysrootLock, deployment: &ostree::Deployment) -> Result<()> {
@@ -835,6 +893,11 @@ fn soft_reboot_staged(sysroot: &SysrootLock) -> Result<()> {
835893
.find(|d| d.is_staged())
836894
.ok_or_else(|| anyhow::anyhow!("Failed to find staged deployment"))?;
837895

896+
// Check SELinux policy compatibility before allowing soft reboot
897+
if let Some(booted_deployment) = sysroot.booted_deployment() {
898+
check_selinux_policy_for_soft_reboot(sysroot, &booted_deployment, staged_deployment)?;
899+
}
900+
838901
prepare_soft_reboot(sysroot, staged_deployment)?;
839902
Ok(())
840903
}
@@ -849,6 +912,13 @@ fn soft_reboot_rollback(booted_ostree: &BootedOstree<'_>) -> Result<()> {
849912
.first()
850913
.ok_or_else(|| anyhow::anyhow!("No rollback deployment found!"))?;
851914

915+
// Check SELinux policy compatibility before allowing soft reboot
916+
check_selinux_policy_for_soft_reboot(
917+
booted_ostree.sysroot,
918+
&booted_ostree.deployment,
919+
target_deployment,
920+
)?;
921+
852922
prepare_soft_reboot(booted_ostree.sysroot, target_deployment)
853923
}
854924

0 commit comments

Comments
 (0)