Files
podman/pkg/util/mountOpts.go
Matthew Heon 96812dc490 Fix addition of mount options when using RO tmpfs
For read-only containers set to create tmpfs filesystems over
/run and other common destinations, we were incorrectly setting
mount options, resulting in duplicate mount options.

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
2019-08-28 14:28:18 -04:00

130 lines
4.0 KiB
Go

package util
import (
"strings"
"github.com/pkg/errors"
)
var (
// ErrBadMntOption indicates that an invalid mount option was passed.
ErrBadMntOption = errors.Errorf("invalid mount option")
// ErrDupeMntOption indicates that a duplicate mount option was passed.
ErrDupeMntOption = errors.Errorf("duplicate mount option passed")
)
// DefaultMountOptions sets default mount options for ProcessOptions.
type DefaultMountOptions struct {
Noexec bool
Nosuid bool
Nodev bool
}
// ProcessOptions parses the options for a bind or tmpfs mount and ensures that
// they are sensible and follow convention. The isTmpfs variable controls
// whether extra, tmpfs-specific options will be allowed.
// The defaults variable controls default mount options that will be set. If it
// is not included, they will be set unconditionally.
func ProcessOptions(options []string, isTmpfs bool, defaults *DefaultMountOptions) ([]string, error) {
var (
foundWrite, foundSize, foundProp, foundMode, foundExec, foundSuid, foundDev, foundCopyUp, foundBind, foundZ bool
)
for _, opt := range options {
// Some options have parameters - size, mode
splitOpt := strings.SplitN(opt, "=", 2)
switch splitOpt[0] {
case "exec", "noexec":
if foundExec {
return nil, errors.Wrapf(ErrDupeMntOption, "only one of 'noexec' and 'exec' can be used")
}
foundExec = true
case "suid", "nosuid":
if foundSuid {
return nil, errors.Wrapf(ErrDupeMntOption, "only one of 'nosuid' and 'suid' can be used")
}
foundSuid = true
case "nodev", "dev":
if foundDev {
return nil, errors.Wrapf(ErrDupeMntOption, "only one of 'nodev' and 'dev' can be used")
}
foundDev = true
case "rw", "ro":
if foundWrite {
return nil, errors.Wrapf(ErrDupeMntOption, "only one of 'rw' and 'ro' can be used")
}
foundWrite = true
case "private", "rprivate", "slave", "rslave", "shared", "rshared":
if foundProp {
return nil, errors.Wrapf(ErrDupeMntOption, "only one root propagation mode can be used")
}
foundProp = true
case "size":
if !isTmpfs {
return nil, errors.Wrapf(ErrBadMntOption, "the 'size' option is only allowed with tmpfs mounts")
}
if foundSize {
return nil, errors.Wrapf(ErrDupeMntOption, "only one tmpfs size can be specified")
}
foundSize = true
case "mode":
if !isTmpfs {
return nil, errors.Wrapf(ErrBadMntOption, "the 'mode' option is only allowed with tmpfs mounts")
}
if foundMode {
return nil, errors.Wrapf(ErrDupeMntOption, "only one tmpfs mode can be specified")
}
foundMode = true
case "tmpcopyup":
if !isTmpfs {
return nil, errors.Wrapf(ErrBadMntOption, "the 'tmpcopyup' option is only allowed with tmpfs mounts")
}
if foundCopyUp {
return nil, errors.Wrapf(ErrDupeMntOption, "the 'tmpcopyup' option can only be set once")
}
foundCopyUp = true
case "bind", "rbind":
if isTmpfs {
return nil, errors.Wrapf(ErrBadMntOption, "the 'bind' and 'rbind' options are not allowed with tmpfs mounts")
}
if foundBind {
return nil, errors.Wrapf(ErrDupeMntOption, "only one of 'rbind' and 'bind' can be used")
}
foundBind = true
case "z", "Z":
if isTmpfs {
return nil, errors.Wrapf(ErrBadMntOption, "the 'z' and 'Z' options are not allowed with tmpfs mounts")
}
if foundZ {
return nil, errors.Wrapf(ErrDupeMntOption, "only one of 'z' and 'Z' can be used")
}
default:
return nil, errors.Wrapf(ErrBadMntOption, "unknown mount option %q", opt)
}
}
if !foundWrite {
options = append(options, "rw")
}
if !foundProp {
options = append(options, "rprivate")
}
if !foundExec && (defaults == nil || defaults.Noexec) {
options = append(options, "noexec")
}
if !foundSuid && (defaults == nil || defaults.Nosuid) {
options = append(options, "nosuid")
}
if !foundDev && (defaults == nil || defaults.Nodev) {
options = append(options, "nodev")
}
if isTmpfs && !foundCopyUp {
options = append(options, "tmpcopyup")
}
if !isTmpfs && !foundBind {
options = append(options, "rbind")
}
return options, nil
}