@@ -525,7 +525,18 @@ impl Wrappable for CreateRequest {
525525
526526 if target_ns. contains ( & Namespace :: User ) {
527527 debug ! ( "child has dropped into its own userns, configuring from supervisor" ) ;
528- self . prepare_userns ( pid) ?;
528+ // In the two-stage path, the child calls pivot_fs() before signaling.
529+ // pivot_root() changes /proc for the parent too.
530+ // If a PID namespace was created, the new /proc shows the child as PID 1
531+ // (not its host PID), so we must use 1 to find it in /proc.
532+ // Without a PID namespace, the new proc mount still shows global PIDs.
533+ let userns_pid =
534+ if !skip_two_stage_userns && target_ns. contains ( & Namespace :: Pid ) {
535+ 1
536+ } else {
537+ pid
538+ } ;
539+ self . prepare_userns ( userns_pid) ?;
529540 }
530541
531542 // The supervisor has now configured the user namespace, so let the first process run.
@@ -548,9 +559,22 @@ impl Wrappable for CreateRequest {
548559
549560 let mut pef = unsafe { File :: from_raw_fd ( parent_efd) } ;
550561
551- if !skip_two_stage_userns && target_ns. contains ( & Namespace :: User ) {
552- debug ! ( "unsharing user namespace" ) ;
553- unshare ( & vec ! [ Namespace :: User ] ) ?;
562+ if !skip_two_stage_userns {
563+ // The mount namespace was unshared in the parent under the initial user
564+ // namespace context. Mount operations must happen before we enter the new
565+ // user namespace, otherwise the child's user namespace won't own the mount
566+ // namespace and operations on it will fail with EPERM.
567+ if target_ns. contains ( & Namespace :: Mount ) {
568+ self . pivot_fs ( ) ?;
569+ } else {
570+ warn ! ( "mount namespace not present in requested namespaces, trying to work anyway..." ) ;
571+ warn ! ( "this is an insecure configuration!" ) ;
572+ }
573+
574+ if target_ns. contains ( & Namespace :: User ) {
575+ debug ! ( "unsharing user namespace" ) ;
576+ unshare ( & vec ! [ Namespace :: User ] ) ?;
577+ }
554578 }
555579
556580 debug ! ( "signalling supervisor to do configuration" ) ;
@@ -563,12 +587,15 @@ impl Wrappable for CreateRequest {
563587 let mut buf = [ 0u8 ; 8 ] ;
564588 cef. read_exact ( & mut buf) ?;
565589
566- // We are configured, now do the mount stuff?
567- if target_ns. contains ( & Namespace :: Mount ) {
568- self . pivot_fs ( ) ?;
569- } else {
570- warn ! ( "mount namespace not present in requested namespaces, trying to work anyway..." ) ;
571- warn ! ( "this is an insecure configuration!" ) ;
590+ if skip_two_stage_userns {
591+ // In two-stage mode, mounts are deferred until after
592+ // UID/GID namespace has been configured by the supervisor.
593+ if target_ns. contains ( & Namespace :: Mount ) {
594+ self . pivot_fs ( ) ?;
595+ } else {
596+ warn ! ( "mount namespace not present in requested namespaces, trying to work anyway..." ) ;
597+ warn ! ( "this is an insecure configuration!" ) ;
598+ }
572599 }
573600
574601 debug ! ( "mount tree finalized, doing final prep" ) ;
0 commit comments