diff --git a/staging/src/k8s.io/mount-utils/mount_linux.go b/staging/src/k8s.io/mount-utils/mount_linux.go index 07ce76de198..150dbe206d8 100644 --- a/staging/src/k8s.io/mount-utils/mount_linux.go +++ b/staging/src/k8s.io/mount-utils/mount_linux.go @@ -35,6 +35,7 @@ import ( "github.com/moby/sys/mountinfo" "golang.org/x/sys/unix" + libcontaineruserns "github.com/opencontainers/runc/libcontainer/userns" "k8s.io/klog/v2" utilexec "k8s.io/utils/exec" ) @@ -111,6 +112,47 @@ func (mounter *Mounter) hasSystemd() bool { return *mounter.withSystemd } +// Do a bind mount including the needed remount for applying the bind opts. +// If the remount fails and we are running in a user namespace +// figure out if the source filesystem has the ro, nodev, noexec, nosuid, +// noatime, relatime or nodiratime flag set and try another remount with the found flags. +func (mounter *Mounter) bindMountSensitive(mounterPath string, mountCmd string, source string, target string, fstype string, bindOpts []string, bindRemountOpts []string, bindRemountOptsSensitive []string, mountFlags []string, systemdMountRequired bool) error { + err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOptsSensitive, mountFlags, systemdMountRequired) + if err != nil { + return err + } + err = mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, mountFlags, systemdMountRequired) + if libcontaineruserns.RunningInUserNS() { + if err == nil { + return nil + } + // Check if the source has ro, nodev, noexec, nosuid, noatime, relatime, + // nodiratime flag... + var s unix.Statfs_t + if err := unix.Statfs(source, &s); err != nil { + return &os.PathError{Op: "statfs", Path: source, Err: err} + } + // ... and retry the mount with flags found above. + flagMapping := map[int]string{ + unix.MS_RDONLY: "ro", + unix.MS_NODEV: "nodev", + unix.MS_NOEXEC: "noexec", + unix.MS_NOSUID: "nosuid", + unix.MS_NOATIME: "noatime", + unix.MS_RELATIME: "relatime", + unix.MS_NODIRATIME: "nodiratime", + } + for k, v := range flagMapping { + if int(s.Flags)&k == k { + bindRemountOpts = append(bindRemountOpts, v) + } + } + return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, mountFlags, systemdMountRequired) + } else { + return err + } +} + // Mount mounts source to target as fstype with given options. 'source' and 'fstype' must // be an empty string in case it's not required, e.g. for remount, or for auto filesystem // type, where kernel handles fstype for you. The mount 'options' is a list of options, @@ -131,11 +173,7 @@ func (mounter *Mounter) MountSensitive(source string, target string, fstype stri mounterPath := "" bind, bindOpts, bindRemountOpts, bindRemountOptsSensitive := MakeBindOptsSensitive(options, sensitiveOptions) if bind { - err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOptsSensitive, nil /* mountFlags */, mounter.trySystemd) - if err != nil { - return err - } - return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, nil /* mountFlags */, mounter.trySystemd) + return mounter.bindMountSensitive(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOpts, bindRemountOptsSensitive, nil /* mountFlags */, mounter.trySystemd) } // The list of filesystems that require containerized mounter on GCI image cluster fsTypesNeedMounter := map[string]struct{}{ @@ -160,11 +198,7 @@ func (mounter *Mounter) MountSensitiveWithoutSystemdWithMountFlags(source string mounterPath := "" bind, bindOpts, bindRemountOpts, bindRemountOptsSensitive := MakeBindOptsSensitive(options, sensitiveOptions) if bind { - err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOptsSensitive, mountFlags, false) - if err != nil { - return err - } - return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, mountFlags, false) + return mounter.bindMountSensitive(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOpts, bindRemountOptsSensitive, mountFlags, false) } // The list of filesystems that require containerized mounter on GCI image cluster fsTypesNeedMounter := map[string]struct{}{