@@ -10,6 +10,7 @@ use crate::{
1010 bootc_composefs:: {
1111 boot:: BootType ,
1212 repo:: get_imgref,
13+ selinux:: are_selinux_policies_compatible,
1314 utils:: { compute_store_boot_digest_for_uki, get_uki_cmdline} ,
1415 } ,
1516 composefs_consts:: {
@@ -59,6 +60,13 @@ pub(crate) struct ComposefsCmdline {
5960 pub digest : Box < str > ,
6061}
6162
63+ /// Information about a deployment for soft reboot comparison
64+ struct DeploymentBootInfo < ' a > {
65+ boot_digest : & ' a str ,
66+ full_cmdline : & ' a Cmdline < ' a > ,
67+ verity : & ' a str ,
68+ }
69+
6270impl ComposefsCmdline {
6371 pub ( crate ) fn new ( s : & str ) -> Self {
6472 let ( insecure, digest_str) = s
@@ -79,9 +87,14 @@ impl std::fmt::Display for ComposefsCmdline {
7987 }
8088}
8189
90+ /// The JSON schema for staged deployment information
91+ /// stored in /run/composefs/staged-deployment
8292#[ derive( Debug , Serialize , Deserialize ) ]
8393pub ( crate ) struct StagedDeployment {
94+ /// The id (verity hash of the EROFS image) of the staged deployment
8495 pub ( crate ) depl_id : String ,
96+ /// Whether to finalize this staged deployment on reboot or not
97+ /// This also maps to `download_only` field in `BootEntry`
8598 pub ( crate ) finalization_locked : bool ,
8699}
87100
@@ -371,7 +384,7 @@ fn set_soft_reboot_capability(
371384 storage : & Storage ,
372385 host : & mut Host ,
373386 bls_entries : Option < Vec < BLSConfig > > ,
374- cmdline : & ComposefsCmdline ,
387+ booted_cmdline : & ComposefsCmdline ,
375388) -> Result < ( ) > {
376389 let booted = host. require_composefs_booted ( ) ?;
377390
@@ -387,10 +400,10 @@ fn set_soft_reboot_capability(
387400 // vector to check for existence of an entry
388401 bls_entries. extend ( staged_entries) ;
389402
390- set_reboot_capable_type1_deployments ( cmdline , host, bls_entries)
403+ set_reboot_capable_type1_deployments ( storage , booted_cmdline , host, bls_entries)
391404 }
392405
393- BootType :: Uki => set_reboot_capable_uki_deployments ( storage, cmdline , host) ,
406+ BootType :: Uki => set_reboot_capable_uki_deployments ( storage, booted_cmdline , host) ,
394407 }
395408}
396409
@@ -430,6 +443,7 @@ fn compare_cmdline_skip_cfs(first: &Cmdline<'_>, second: &Cmdline<'_>) -> bool {
430443
431444#[ context( "Setting soft reboot capability for Type1 entries" ) ]
432445fn set_reboot_capable_type1_deployments (
446+ storage : & Storage ,
433447 booted_cmdline : & ComposefsCmdline ,
434448 host : & mut Host ,
435449 bls_entries : Vec < BLSConfig > ,
@@ -445,7 +459,13 @@ fn set_reboot_capable_type1_deployments(
445459 let booted_bls_entry = find_bls_entry ( & * booted_cmdline. digest , & bls_entries) ?
446460 . ok_or_else ( || anyhow:: anyhow!( "Booted BLS entry not found" ) ) ?;
447461
448- let booted_cmdline = booted_bls_entry. get_cmdline ( ) ?;
462+ let booted_full_cmdline = booted_bls_entry. get_cmdline ( ) ?;
463+
464+ let booted_info = DeploymentBootInfo {
465+ boot_digest : booted_boot_digest,
466+ full_cmdline : booted_full_cmdline,
467+ verity : & booted_cmdline. digest ,
468+ } ;
449469
450470 for depl in host
451471 . status
@@ -454,46 +474,64 @@ fn set_reboot_capable_type1_deployments(
454474 . chain ( host. status . rollback . iter_mut ( ) )
455475 . chain ( host. status . other_deployments . iter_mut ( ) )
456476 {
457- let entry = find_bls_entry ( & depl. require_composefs ( ) ?. verity , & bls_entries) ?
477+ let depl_verity = & depl. require_composefs ( ) ?. verity ;
478+
479+ let entry = find_bls_entry ( & depl_verity, & bls_entries) ?
458480 . ok_or_else ( || anyhow:: anyhow!( "Entry not found" ) ) ?;
459481
460482 let depl_cmdline = entry. get_cmdline ( ) ?;
461483
462- depl. soft_reboot_capable = is_soft_rebootable (
463- depl. composefs_boot_digest ( ) ?,
464- booted_boot_digest,
465- depl_cmdline,
466- booted_cmdline,
467- ) ;
484+ let target_info = DeploymentBootInfo {
485+ boot_digest : depl. composefs_boot_digest ( ) ?,
486+ full_cmdline : depl_cmdline,
487+ verity : & depl_verity,
488+ } ;
489+
490+ depl. soft_reboot_capable =
491+ is_soft_rebootable ( storage, booted_cmdline, & booted_info, & target_info) ?;
468492 }
469493
470494 Ok ( ( ) )
471495}
472496
497+ /// Determines whether a soft reboot can be performed between the currently booted
498+ /// deployment and a target deployment.
499+ ///
500+ /// # Arguments
501+ ///
502+ /// * `storage` - The bootc storage backend
503+ /// * `booted_cmdline` - The composefs command line parameters of the currently booted deployment
504+ /// * `booted` - Boot information for the currently booted deployment
505+ /// * `target` - Boot information for the target deployment
473506fn is_soft_rebootable (
474- depl_boot_digest : & str ,
475- booted_boot_digest : & str ,
476- depl_cmdline : & Cmdline ,
477- booted_cmdline : & Cmdline ,
478- ) -> bool {
479- if depl_boot_digest != booted_boot_digest {
507+ storage : & Storage ,
508+ booted_cmdline : & ComposefsCmdline ,
509+ booted : & DeploymentBootInfo ,
510+ target : & DeploymentBootInfo ,
511+ ) -> Result < bool > {
512+ if target . boot_digest != booted . boot_digest {
480513 tracing:: debug!( "Soft reboot not allowed due to kernel skew" ) ;
481- return false ;
514+ return Ok ( false ) ;
482515 }
483516
484- if depl_cmdline . as_bytes ( ) . len ( ) != booted_cmdline . as_bytes ( ) . len ( ) {
517+ if target . full_cmdline . as_bytes ( ) . len ( ) != booted . full_cmdline . as_bytes ( ) . len ( ) {
485518 tracing:: debug!( "Soft reboot not allowed due to differing cmdline" ) ;
486- return false ;
519+ return Ok ( false ) ;
487520 }
488521
489- return compare_cmdline_skip_cfs ( depl_cmdline, booted_cmdline)
490- && compare_cmdline_skip_cfs ( booted_cmdline, depl_cmdline) ;
522+ let cmdline_eq = compare_cmdline_skip_cfs ( target. full_cmdline , booted. full_cmdline )
523+ && compare_cmdline_skip_cfs ( booted. full_cmdline , target. full_cmdline ) ;
524+
525+ let selinux_compatible =
526+ are_selinux_policies_compatible ( storage, booted_cmdline, target. verity ) ?;
527+
528+ return Ok ( cmdline_eq && selinux_compatible) ;
491529}
492530
493531#[ context( "Setting soft reboot capability for UKI deployments" ) ]
494532fn set_reboot_capable_uki_deployments (
495533 storage : & Storage ,
496- cmdline : & ComposefsCmdline ,
534+ booted_cmdline : & ComposefsCmdline ,
497535 host : & mut Host ,
498536) -> Result < ( ) > {
499537 let booted = host
@@ -505,10 +543,16 @@ fn set_reboot_capable_uki_deployments(
505543 // Since older booted systems won't have the boot digest for UKIs
506544 let booted_boot_digest = match booted. composefs_boot_digest ( ) {
507545 Ok ( d) => d,
508- Err ( _) => & compute_store_boot_digest_for_uki ( storage, & cmdline . digest ) ?,
546+ Err ( _) => & compute_store_boot_digest_for_uki ( storage, & booted_cmdline . digest ) ?,
509547 } ;
510548
511- let booted_cmdline = get_uki_cmdline ( storage, & booted. require_composefs ( ) ?. verity ) ?;
549+ let booted_full_cmdline = get_uki_cmdline ( storage, & booted_cmdline. digest ) ?;
550+
551+ let booted_info = DeploymentBootInfo {
552+ boot_digest : booted_boot_digest,
553+ full_cmdline : & booted_full_cmdline,
554+ verity : & booted_cmdline. digest ,
555+ } ;
512556
513557 for deployment in host
514558 . status
@@ -517,23 +561,24 @@ fn set_reboot_capable_uki_deployments(
517561 . chain ( host. status . rollback . iter_mut ( ) )
518562 . chain ( host. status . other_deployments . iter_mut ( ) )
519563 {
564+ let depl_verity = & deployment. require_composefs ( ) ?. verity ;
565+
520566 // Since older booted systems won't have the boot digest for UKIs
521567 let depl_boot_digest = match deployment. composefs_boot_digest ( ) {
522568 Ok ( d) => d,
523- Err ( _) => & compute_store_boot_digest_for_uki (
524- storage,
525- & deployment. require_composefs ( ) ?. verity ,
526- ) ?,
569+ Err ( _) => & compute_store_boot_digest_for_uki ( storage, depl_verity) ?,
527570 } ;
528571
529572 let depl_cmdline = get_uki_cmdline ( storage, & deployment. require_composefs ( ) ?. verity ) ?;
530573
531- deployment. soft_reboot_capable = is_soft_rebootable (
532- depl_boot_digest,
533- booted_boot_digest,
534- & depl_cmdline,
535- & booted_cmdline,
536- ) ;
574+ let target_info = DeploymentBootInfo {
575+ boot_digest : depl_boot_digest,
576+ full_cmdline : & depl_cmdline,
577+ verity : depl_verity,
578+ } ;
579+
580+ deployment. soft_reboot_capable =
581+ is_soft_rebootable ( storage, booted_cmdline, & booted_info, & target_info) ?;
537582 }
538583
539584 Ok ( ( ) )
0 commit comments