Skip to content

Commit 30452df

Browse files
committed
Fix mount order for single-stage
1 parent 4e9a9cc commit 30452df

1 file changed

Lines changed: 37 additions & 10 deletions

File tree

src/wrap.rs

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)