@@ -11,7 +11,7 @@ use std::path::PathBuf;
1111use std:: process;
1212use std:: ptr;
1313
14- use crate :: caps:: { CapabilityBit , get_caps, set_caps} ;
14+ use crate :: caps:: { CapabilityBit , get_caps, set_caps, set_keep_caps } ;
1515use crate :: cgroup:: CGroup ;
1616use crate :: config:: {
1717 AttachRequest , Capabilities , CreateDirMutation , CreateRequest , ExecutableSpec , IdMapping ,
@@ -508,8 +508,6 @@ impl Wrappable for CreateRequest {
508508 unshare ( & vec ! [ Namespace :: User ] ) ?;
509509 }
510510
511- apply_capabilities ( self . capabilities . as_ref ( ) ) ?;
512-
513511 debug ! ( "signalling supervisor to do configuration" ) ;
514512 pef. write_all ( & 2_u64 . to_ne_bytes ( ) ) ?;
515513 pef. flush ( ) ?;
@@ -520,6 +518,17 @@ impl Wrappable for CreateRequest {
520518 let mut buf = [ 0u8 ; 8 ] ;
521519 cef. read_exact ( & mut buf) ?;
522520
521+ // We need to toggle SECBIT before we change UID/GID,
522+ // or else changing UID/GID may cause us to lose the capabilities
523+ // we need to explicitly drop capabilities later on.
524+ set_keep_caps ( ) ?;
525+ // Set these *first*, before we exec. Otherwise
526+ // we may not be able to switch after dropping caps.
527+ apply_gid_uid ( self . exec . gid , self . exec . uid ) ?;
528+ // Now, we can synchronize effective/inherited/permitted caps
529+ // as a final step.
530+ apply_capabilities ( self . capabilities . as_ref ( ) ) ?;
531+
523532 debug ! ( "ready to launch workload" ) ;
524533 self . exec . execute ( )
525534 }
@@ -556,26 +565,6 @@ impl ExecutableSpec {
556565 let mut env_charptrs: Vec < _ > = env_cstrings. iter ( ) . map ( |arg| arg. as_ptr ( ) ) . collect ( ) ;
557566 env_charptrs. push ( ptr:: null ( ) ) ;
558567
559- if let Some ( target_uid) = self . uid {
560- unsafe {
561- // Check this to avoid a spurious log if we don't need to change,
562- // because we are already running as the target UID.
563- if libc:: getuid ( ) != target_uid && libc:: setuid ( target_uid as libc:: uid_t ) < 0 {
564- warn ! ( "unable to set target UID: {:?}" , Error :: last_os_error( ) ) ;
565- }
566- }
567- }
568-
569- if let Some ( target_gid) = self . gid {
570- unsafe {
571- // Check this to avoid a spurious log if we don't need to change,
572- // because we are already running as the target GID.
573- if libc:: getgid ( ) != target_gid && libc:: setgid ( target_gid as libc:: gid_t ) < 0 {
574- warn ! ( "unable to set target GID: {:?}" , Error :: last_os_error( ) ) ;
575- }
576- }
577- }
578-
579568 if let Some ( wd) = & self . working_directory {
580569 env:: set_current_dir ( wd. clone ( ) ) ?;
581570 }
@@ -718,6 +707,32 @@ impl Mutatable for CreateDirMutation {
718707 }
719708}
720709
710+ fn apply_gid_uid ( gid : Option < u32 > , uid : Option < u32 > ) -> Result < ( ) > {
711+ // NOTE - order is important here - must change GID *before* changing UID, to avoid
712+ // locking oneself out of the GID change with an "operation not permitted" error
713+ if let Some ( target_gid) = gid {
714+ unsafe {
715+ // Check this to avoid a spurious log if we don't need to change,
716+ // because we are already running as the target GID.
717+ if libc:: getgid ( ) != target_gid && libc:: setgid ( target_gid as libc:: gid_t ) < 0 {
718+ warn ! ( "unable to set target GID: {:?}" , Error :: last_os_error( ) ) ;
719+ }
720+ }
721+ }
722+
723+ if let Some ( target_uid) = uid {
724+ unsafe {
725+ // Check this to avoid a spurious log if we don't need to change,
726+ // because we are already running as the target UID.
727+ if libc:: getuid ( ) != target_uid && libc:: setuid ( target_uid as libc:: uid_t ) < 0 {
728+ warn ! ( "unable to set target UID: {:?}" , Error :: last_os_error( ) ) ;
729+ }
730+ }
731+ }
732+
733+ Ok ( ( ) )
734+ }
735+
721736fn apply_capabilities ( capabilities : Option < & Capabilities > ) -> Result < ( ) > {
722737 let Some ( caps) = capabilities else {
723738 return Ok ( ( ) ) ;
0 commit comments