Merge pull request #5676 from kolyshkin/volume-flags-alt

Fix/improve pkg/storage.InitFSMounts
This commit is contained in:
OpenShift Merge Robot
2020-04-03 18:34:01 +02:00
committed by GitHub
7 changed files with 58 additions and 84 deletions

View File

@ -1334,7 +1334,7 @@ func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption {
} }
destinations[vol.Dest] = true destinations[vol.Dest] = true
mountOpts, err := util.ProcessOptions(vol.Options, false, nil) mountOpts, err := util.ProcessOptions(vol.Options, false, "")
if err != nil { if err != nil {
return errors.Wrapf(err, "error processing options for named volume %q mounted at %q", vol.Name, vol.Dest) return errors.Wrapf(err, "error processing options for named volume %q mounted at %q", vol.Name, vol.Dest)
} }

View File

@ -381,11 +381,9 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
// BIND MOUNTS // BIND MOUNTS
configSpec.Mounts = SupercedeUserMounts(userMounts, configSpec.Mounts) configSpec.Mounts = SupercedeUserMounts(userMounts, configSpec.Mounts)
// Process mounts to ensure correct options // Process mounts to ensure correct options
finalMounts, err := InitFSMounts(configSpec.Mounts) if err := InitFSMounts(configSpec.Mounts); err != nil {
if err != nil {
return nil, err return nil, err
} }
configSpec.Mounts = finalMounts
// BLOCK IO // BLOCK IO
blkio, err := config.CreateBlockIO() blkio, err := config.CreateBlockIO()

View File

@ -10,7 +10,6 @@ import (
"github.com/containers/buildah/pkg/parse" "github.com/containers/buildah/pkg/parse"
"github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/util" "github.com/containers/libpod/pkg/util"
pmount "github.com/containers/storage/pkg/mount"
spec "github.com/opencontainers/runtime-spec/specs-go" spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -855,75 +854,22 @@ func SupercedeUserMounts(mounts []spec.Mount, configMount []spec.Mount) []spec.M
} }
// Ensure mount options on all mounts are correct // Ensure mount options on all mounts are correct
func InitFSMounts(inputMounts []spec.Mount) ([]spec.Mount, error) { func InitFSMounts(mounts []spec.Mount) error {
// We need to look up mounts so we can figure out the proper mount flags for i, m := range mounts {
// to apply. switch {
systemMounts, err := pmount.GetMounts() case m.Type == TypeBind:
if err != nil { opts, err := util.ProcessOptions(m.Options, false, m.Source)
return nil, errors.Wrapf(err, "error retrieving system mounts to look up mount options")
}
// TODO: We probably don't need to re-build the mounts array
var mounts []spec.Mount
for _, m := range inputMounts {
if m.Type == TypeBind {
baseMnt, err := findMount(m.Destination, systemMounts)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error looking up mountpoint for mount %s", m.Destination) return err
} }
var noexec, nosuid, nodev bool mounts[i].Options = opts
for _, baseOpt := range strings.Split(baseMnt.Opts, ",") { case m.Type == TypeTmpfs && filepath.Clean(m.Destination) != "/dev":
switch baseOpt { opts, err := util.ProcessOptions(m.Options, true, "")
case "noexec":
noexec = true
case "nosuid":
nosuid = true
case "nodev":
nodev = true
}
}
defaultMountOpts := new(util.DefaultMountOptions)
defaultMountOpts.Noexec = noexec
defaultMountOpts.Nosuid = nosuid
defaultMountOpts.Nodev = nodev
opts, err := util.ProcessOptions(m.Options, false, defaultMountOpts)
if err != nil { if err != nil {
return nil, err return err
} }
m.Options = opts mounts[i].Options = opts
} }
if m.Type == TypeTmpfs && filepath.Clean(m.Destination) != "/dev" {
opts, err := util.ProcessOptions(m.Options, true, nil)
if err != nil {
return nil, err
}
m.Options = opts
}
mounts = append(mounts, m)
} }
return mounts, nil return nil
}
// TODO: We could make this a bit faster by building a tree of the mountpoints
// and traversing it to identify the correct mount.
func findMount(target string, mounts []*pmount.Info) (*pmount.Info, error) {
var err error
target, err = filepath.Abs(target)
if err != nil {
return nil, errors.Wrapf(err, "cannot resolve %s", target)
}
var bestSoFar *pmount.Info
for _, i := range mounts {
if bestSoFar != nil && len(bestSoFar.Mountpoint) > len(i.Mountpoint) {
// Won't be better than what we have already found
continue
}
if strings.HasPrefix(target, i.Mountpoint) {
bestSoFar = i
}
}
return bestSoFar, nil
} }

View File

@ -215,11 +215,9 @@ func (s *SpecGenerator) toOCISpec(rt *libpod.Runtime, newImage *image.Image) (*s
// BIND MOUNTS // BIND MOUNTS
configSpec.Mounts = createconfig.SupercedeUserMounts(s.Mounts, configSpec.Mounts) configSpec.Mounts = createconfig.SupercedeUserMounts(s.Mounts, configSpec.Mounts)
// Process mounts to ensure correct options // Process mounts to ensure correct options
finalMounts, err := createconfig.InitFSMounts(configSpec.Mounts) if err := createconfig.InitFSMounts(configSpec.Mounts); err != nil {
if err != nil {
return nil, err return nil, err
} }
configSpec.Mounts = finalMounts
// Add annotations // Add annotations
if configSpec.Annotations == nil { if configSpec.Annotations == nil {

View File

@ -13,19 +13,17 @@ var (
ErrDupeMntOption = errors.Errorf("duplicate mount option passed") ErrDupeMntOption = errors.Errorf("duplicate mount option passed")
) )
// DefaultMountOptions sets default mount options for ProcessOptions. type defaultMountOptions struct {
type DefaultMountOptions struct { noexec bool
Noexec bool nosuid bool
Nosuid bool nodev bool
Nodev bool
} }
// ProcessOptions parses the options for a bind or tmpfs mount and ensures that // ProcessOptions parses the options for a bind or tmpfs mount and ensures that
// they are sensible and follow convention. The isTmpfs variable controls // they are sensible and follow convention. The isTmpfs variable controls
// whether extra, tmpfs-specific options will be allowed. // whether extra, tmpfs-specific options will be allowed.
// The defaults variable controls default mount options that will be set. If it // The sourcePath variable, if not empty, contains a bind mount source.
// is not included, they will be set unconditionally. func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string, error) {
func ProcessOptions(options []string, isTmpfs bool, defaults *DefaultMountOptions) ([]string, error) {
var ( var (
foundWrite, foundSize, foundProp, foundMode, foundExec, foundSuid, foundDev, foundCopyUp, foundBind, foundZ bool foundWrite, foundSize, foundProp, foundMode, foundExec, foundSuid, foundDev, foundCopyUp, foundBind, foundZ bool
) )
@ -122,13 +120,17 @@ func ProcessOptions(options []string, isTmpfs bool, defaults *DefaultMountOption
if !foundProp { if !foundProp {
newOptions = append(newOptions, "rprivate") newOptions = append(newOptions, "rprivate")
} }
if !foundExec && (defaults == nil || defaults.Noexec) { defaults, err := getDefaultMountOptions(sourcePath)
if err != nil {
return nil, err
}
if !foundExec && defaults.noexec {
newOptions = append(newOptions, "noexec") newOptions = append(newOptions, "noexec")
} }
if !foundSuid && (defaults == nil || defaults.Nosuid) { if !foundSuid && defaults.nosuid {
newOptions = append(newOptions, "nosuid") newOptions = append(newOptions, "nosuid")
} }
if !foundDev && (defaults == nil || defaults.Nodev) { if !foundDev && defaults.nodev {
newOptions = append(newOptions, "nodev") newOptions = append(newOptions, "nodev")
} }
if isTmpfs && !foundCopyUp { if isTmpfs && !foundCopyUp {

View File

@ -0,0 +1,23 @@
package util
import (
"os"
"golang.org/x/sys/unix"
)
func getDefaultMountOptions(path string) (defaultMountOptions, error) {
opts := defaultMountOptions{true, true, true}
if path == "" {
return opts, nil
}
var statfs unix.Statfs_t
if e := unix.Statfs(path, &statfs); e != nil {
return opts, &os.PathError{Op: "statfs", Path: path, Err: e}
}
opts.nodev = (statfs.Flags&unix.MS_NODEV == unix.MS_NODEV)
opts.noexec = (statfs.Flags&unix.MS_NOEXEC == unix.MS_NOEXEC)
opts.nosuid = (statfs.Flags&unix.MS_NOSUID == unix.MS_NOSUID)
return opts, nil
}

View File

@ -0,0 +1,7 @@
// +build !linux
package util
func getDefaultMountOptions(path string) (opts defaultMountOptions, err error) {
return
}