aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@pm.me>2019-04-24 13:42:41 -0400
committerMatthew Heon <matthew.heon@pm.me>2019-05-01 10:19:05 -0400
commit2698c82240e4b9be5aaac787f8008fd6b74f645b (patch)
tree9d66614438e4508d4e28ac8ff08114a918b2c1a0 /pkg
parent7a421a807c38dbe878b59c637f67c289cea7d418 (diff)
downloadpodman-2698c82240e4b9be5aaac787f8008fd6b74f645b.tar.gz
podman-2698c82240e4b9be5aaac787f8008fd6b74f645b.tar.bz2
podman-2698c82240e4b9be5aaac787f8008fd6b74f645b.zip
Add options parsing for tmpfs mounts
This ensures that all tmpfs mounts added by the user, even with the --mount flag, share a few common options (nosuid, noexec, nodev), and options for tmpfs mounts are properly validated to ensure they are correct. Signed-off-by: Matthew Heon <matthew.heon@pm.me>
Diffstat (limited to 'pkg')
-rw-r--r--pkg/spec/storage.go73
1 files changed, 66 insertions, 7 deletions
diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go
index 9660c278f..c838e7204 100644
--- a/pkg/spec/storage.go
+++ b/pkg/spec/storage.go
@@ -28,6 +28,7 @@ var (
badOptionError = errors.Errorf("invalid mount option")
optionArgError = errors.Errorf("must provide an argument for option")
noDestError = errors.Errorf("must set volume destination")
+ dupeOptionError = errors.Errorf("duplicate option passed")
)
// Parse all volume-related options in the create config into a set of mounts
@@ -160,6 +161,14 @@ func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount,
// Final step: maps to arrays
finalMounts := make([]spec.Mount, 0, len(baseMounts))
for _, mount := range baseMounts {
+ // All user-added tmpfs mounts need their options processed.
+ if mount.Type == TypeTmpfs {
+ opts, err := processTmpfsOptions(mount.Options)
+ if err != nil {
+ return nil, nil, err
+ }
+ mount.Options = opts
+ }
finalMounts = append(finalMounts, mount)
}
finalVolumes := make([]*libpod.ContainerNamedVolume, 0, len(baseVolumes))
@@ -414,16 +423,13 @@ func getTmpfsMount(args []string) (spec.Mount, error) {
kv := strings.Split(val, "=")
switch kv[0] {
case "ro", "nosuid", "nodev", "noexec":
- // TODO: detect duplication of these options
newMount.Options = append(newMount.Options, kv[0])
case "tmpfs-mode":
- // TODO: detect duplicate modes
if len(kv) == 1 {
return newMount, errors.Wrapf(optionArgError, kv[0])
}
newMount.Options = append(newMount.Options, fmt.Sprintf("mode=%s", kv[1]))
case "tmpfs-size":
- // TODO: detect duplicate sizes
if len(kv) == 1 {
return newMount, errors.Wrapf(optionArgError, kv[0])
}
@@ -657,7 +663,7 @@ func (config *CreateConfig) getTmpfsMounts() (map[string]spec.Mount, error) {
m := make(map[string]spec.Mount)
for _, i := range config.Tmpfs {
// Default options if nothing passed
- options := []string{"rprivate", "rw", "noexec", "nosuid", "nodev", "size=65536k"}
+ var options []string
spliti := strings.Split(i, ":")
destPath := spliti[0]
if len(spliti) > 1 {
@@ -668,9 +674,6 @@ func (config *CreateConfig) getTmpfsMounts() (map[string]spec.Mount, error) {
return nil, errors.Wrapf(errDuplicateDest, destPath)
}
- // TODO: Do we want to set some default options if the user
- // passed options?
- // TODO: should we validate the options passed in?
mount := spec.Mount{
Destination: destPath,
Type: string(TypeTmpfs),
@@ -739,6 +742,62 @@ func processOptions(options []string) []string {
return options
}
+// Handle options for tmpfs mounts
+func processTmpfsOptions(options []string) ([]string, error) {
+ var (
+ foundWrite, foundSize, foundProp, foundMode bool
+ )
+
+ baseOpts := []string{"noexec", "nosuid", "nodev"}
+ for _, opt := range options {
+ // Some options have parameters - size, mode
+ splitOpt := strings.SplitN(opt, "=", 2)
+ switch splitOpt[0] {
+ case "rw", "ro":
+ if foundWrite {
+ return nil, errors.Wrapf(dupeOptionError, "only one of rw and ro can be used")
+ }
+ foundWrite = true
+ baseOpts = append(baseOpts, opt)
+ case "private", "rprivate", "slave", "rslave", "shared", "rshared":
+ if foundProp {
+ return nil, errors.Wrapf(dupeOptionError, "only one root propagation mode can be used")
+ }
+ foundProp = true
+ baseOpts = append(baseOpts, opt)
+ case "size":
+ if foundSize {
+ return nil, errors.Wrapf(dupeOptionError, "only one tmpfs size can be specified")
+ }
+ foundSize = true
+ baseOpts = append(baseOpts, opt)
+ case "mode":
+ if foundMode {
+ return nil, errors.Wrapf(dupeOptionError, "only one tmpfs mode can be specified")
+ }
+ foundMode = true
+ baseOpts = append(baseOpts, opt)
+ case "noexec", "nodev", "nosuid":
+ // Do nothing. We always include these even if they are
+ // not explicitly requested.
+ default:
+ return nil, errors.Wrapf(badOptionError, "unknown tmpfs option %q", opt)
+ }
+ }
+
+ if !foundWrite {
+ baseOpts = append(baseOpts, "rw")
+ }
+ if !foundSize {
+ baseOpts = append(baseOpts, "size=65536k")
+ }
+ if !foundProp {
+ baseOpts = append(baseOpts, "rprivate")
+ }
+
+ return baseOpts, nil
+}
+
// Supercede existing mounts in the spec with new, user-specified mounts.
// TODO: Should we unmount subtree mounts? E.g., if /tmp/ is mounted by
// one mount, and we already have /tmp/a and /tmp/b, should we remove