Fix bind mounts of filesystems with specific mount options set

Currently bind mounts of filesystems with nodev, noexec, nosuid,
noatime, relatime or nodiratime options set fail if we are running in a
user namespace if the same options are not set for the bind mount.

In case we are running in a user name space fix this by searching the
mount options of the source filesystem for nodev, noexec, nosuid,
noatime, relatime or nodiratime and retry the bind mount with the
options found added.

Signed-off-by: Ruediger Pluem <ruediger.pluem@vodafone.com>
This commit is contained in:
Ruediger Pluem 2023-06-05 13:18:34 +02:00
parent d9c54f69d4
commit 2bdacbf685

View File

@ -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{}{