@@ -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" ) ]
768813fn 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