Skip to content

Commit 8a1a040

Browse files
avagingvisor-bot
authored andcommitted
gofer: Ensure mount flags are applied for bind mounts
The initial mount syscall for a new bind mount ignores provided flags, inheriting the underlying mount's options. To apply custom flags, a subsequent mount call with `MS_BIND|MS_REMOUNT` is required. This change addresses that behavior. PiperOrigin-RevId: 777778148
1 parent 973b2f2 commit 8a1a040

File tree

3 files changed

+56
-14
lines changed

3 files changed

+56
-14
lines changed

runsc/boot/vfs.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,14 @@ func setupContainerVFS(ctx context.Context, info *containerInfo, mntr *container
202202
return fmt.Errorf("failed to create device files: %w", err)
203203
}
204204

205+
if err := mntr.k.VFS().MkdirAllAt(
206+
ctx, procArgs.WorkingDirectory, mnsRoot, rootCreds,
207+
&vfs.MkdirOptions{Mode: 0755}, true, /* mustBeDir */
208+
); err != nil {
209+
return fmt.Errorf("failed to create process working directory %q: %w",
210+
procArgs.WorkingDirectory, err)
211+
}
212+
205213
// We are executing a file directly. Do not resolve the executable path.
206214
if procArgs.File != nil {
207215
return nil

runsc/cmd/gofer.go

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -485,18 +485,6 @@ func (g *Gofer) setupRootFS(spec *specs.Spec, conf *config.Config, goferToHostRP
485485
g.setupDev(spec, conf, root, procPath)
486486
}
487487

488-
// Create working directory if needed.
489-
if spec.Process.Cwd != "" {
490-
dst, err := resolveSymlinks(root, spec.Process.Cwd)
491-
if err != nil {
492-
return fmt.Errorf("resolving symlinks to %q: %v", spec.Process.Cwd, err)
493-
}
494-
log.Infof("Create working directory %q if needed", spec.Process.Cwd)
495-
if err := os.MkdirAll(dst, 0755); err != nil {
496-
return fmt.Errorf("creating working directory %q: %v", spec.Process.Cwd, err)
497-
}
498-
}
499-
500488
// Check if root needs to be remounted as readonly.
501489
if rootfsConf.ShouldUseLisafs() && (spec.Root.Readonly || rootfsConf.ShouldUseOverlayfs()) {
502490
// If root is a mount point but not read-only, we can change mount options
@@ -526,7 +514,7 @@ func (g *Gofer) setupRootFS(spec *specs.Spec, conf *config.Config, goferToHostRP
526514
// setupMounts bind mounts all mounts specified in the spec in their correct
527515
// location inside root. It will resolve relative paths and symlinks. It also
528516
// creates directories as needed.
529-
func (g *Gofer) setupMounts(conf *config.Config, mounts []specs.Mount, root, procPath string, goferToHostRPC *urpc.Client) error {
517+
func (g *Gofer) setupMounts(conf *config.Config, mounts []specs.Mount, root, procPath string, goferToHostRPC *urpc.Client) (retErr error) {
530518
mountIdx := 1 // First index is for rootfs.
531519
for _, m := range mounts {
532520
if !specutils.IsGoferMount(m) {
@@ -569,6 +557,52 @@ func (g *Gofer) setupMounts(conf *config.Config, mounts []specs.Mount, root, pro
569557
return fmt.Errorf("mounting %+v: %v", m, err)
570558
}
571559

560+
dstFD, err := unix.Open(dst, unix.O_PATH|unix.O_CLOEXEC, 0)
561+
if err != nil {
562+
return fmt.Errorf("Open(%s, _, _): %w", dst, err)
563+
}
564+
defer unix.Close(dstFD)
565+
// Apply mount options after creating all mount points.
566+
// Otherwise they can be remounted into read-only.
567+
defer func(dstFD int, flags uint32, dst string) {
568+
path := fmt.Sprintf("/proc/self/fd/%d", dstFD)
569+
// The gofer process doesn't execute anything nativly.
570+
flags |= unix.MS_NOSUID
571+
572+
statfs := unix.Statfs_t{}
573+
if err := unix.Statfs(path, &statfs); err != nil {
574+
retErr = fmt.Errorf("stat dst: %q", dst)
575+
return
576+
}
577+
lockedFlags := uint32(0)
578+
for _, f := range []struct {
579+
st, ms int
580+
}{
581+
// MS_NOSUID are always set.
582+
{unix.ST_RDONLY, unix.MS_RDONLY},
583+
{unix.ST_NOEXEC, unix.MS_NOEXEC},
584+
{unix.ST_NODEV, unix.MS_NODEV},
585+
{unix.ST_NOATIME, unix.MS_NOATIME},
586+
{unix.ST_NODIRATIME, unix.MS_NODIRATIME},
587+
{unix.ST_RELATIME, unix.MS_RELATIME},
588+
} {
589+
if int(statfs.Flags)&f.st == f.st {
590+
lockedFlags |= uint32(f.ms)
591+
}
592+
}
593+
if lockedFlags&unix.MS_NOATIME|unix.MS_RELATIME == 0 {
594+
lockedFlags |= unix.MS_STRICTATIME
595+
}
596+
597+
// The previous SafeSetupAndMount creates a new bind-mount, but
598+
// it doesn't change mount flags. A separate MS_BIND|MS_REMOUNT
599+
// has to be done to apply the mount options.
600+
if err := unix.Mount("", path, "", uintptr(flags|lockedFlags|unix.MS_REMOUNT), ""); err != nil {
601+
retErr = fmt.Errorf("mount dst: %q, flags: %#x, err: %v", dst, flags, err)
602+
return
603+
}
604+
}(dstFD, flags, dst)
605+
572606
// Set propagation options that cannot be set together with other options.
573607
flags = specutils.PropOptionsToFlags(m.Options)
574608
if flags != 0 {

runsc/specutils/fs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func optionsToFlags(opts []string, source map[string]mapping) uint32 {
103103
if m.set {
104104
rv |= m.val
105105
} else {
106-
rv ^= m.val
106+
rv &= ^m.val
107107
}
108108
}
109109
}

0 commit comments

Comments
 (0)