From 8e5b294ac3429b8c59dd014a1583d0d77ea2380a Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Tue, 18 Jun 2019 16:21:40 -0400 Subject: Allow (but ignore) Cached and Delegated volume options These are only used on OS X Docker, and ignored elsewhere - but since they are ignored, they're guaranteed to be safe everywhere, and people are using them. Fixes: #3340 Signed-off-by: Matthew Heon --- pkg/spec/storage.go | 43 +++++++++++++++++++++++++++++++++---------- pkg/util/mountOpts.go | 16 ++++++---------- 2 files changed, 39 insertions(+), 20 deletions(-) (limited to 'pkg') diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go index 283585ef8..c960ace33 100644 --- a/pkg/spec/storage.go +++ b/pkg/spec/storage.go @@ -251,9 +251,11 @@ func (config *CreateConfig) getVolumesFrom(runtime *libpod.Runtime) (map[string] return nil, nil, errors.Errorf("invalid options %q, can only specify 'ro', 'rw', and 'z", splitVol[1]) } options = strings.Split(splitVol[1], ",") - if err := ValidateVolumeOpts(options); err != nil { + opts, err := ValidateVolumeOpts(options) + if err != nil { return nil, nil, err } + options = opts } ctr, err := runtime.LookupContainer(splitVol[0]) if err != nil { @@ -447,9 +449,11 @@ func getBindMount(args []string) (spec.Mount, error) { newMount.Source = newMount.Destination } - if err := ValidateVolumeOpts(newMount.Options); err != nil { + opts, err := ValidateVolumeOpts(newMount.Options) + if err != nil { return newMount, err } + newMount.Options = opts return newMount, nil } @@ -575,35 +579,52 @@ func ValidateVolumeCtrDir(ctrDir string) error { } // ValidateVolumeOpts validates a volume's options -func ValidateVolumeOpts(options []string) error { +func ValidateVolumeOpts(options []string) ([]string, error) { var foundRootPropagation, foundRWRO, foundLabelChange, bindType int + finalOpts := make([]string, 0, len(options)) + discardOpts := []string{"cached", "delegated"} for _, opt := range options { + // The discarded ops are OS X specific volume options introduced + // in a recent Docker version. + // They have no meaning on Linux, so here we silently drop them. + // This matches Docker's behavior (the options are intended to + // be always safe to use, even not on OS X). + bad := false + for _, discard := range discardOpts { + if opt == discard { + bad = true + } + } + if bad { + continue + } switch opt { case "rw", "ro": foundRWRO++ if foundRWRO > 1 { - return errors.Errorf("invalid options %q, can only specify 1 'rw' or 'ro' option", strings.Join(options, ", ")) + return nil, errors.Errorf("invalid options %q, can only specify 1 'rw' or 'ro' option", strings.Join(options, ", ")) } case "z", "Z": foundLabelChange++ if foundLabelChange > 1 { - return errors.Errorf("invalid options %q, can only specify 1 'z' or 'Z' option", strings.Join(options, ", ")) + return nil, errors.Errorf("invalid options %q, can only specify 1 'z' or 'Z' option", strings.Join(options, ", ")) } case "private", "rprivate", "shared", "rshared", "slave", "rslave": foundRootPropagation++ if foundRootPropagation > 1 { - return errors.Errorf("invalid options %q, can only specify 1 '[r]shared', '[r]private' or '[r]slave' option", strings.Join(options, ", ")) + return nil, errors.Errorf("invalid options %q, can only specify 1 '[r]shared', '[r]private' or '[r]slave' option", strings.Join(options, ", ")) } case "bind", "rbind": bindType++ if bindType > 1 { - return errors.Errorf("invalid options %q, can only specify 1 '[r]bind' option", strings.Join(options, ", ")) + return nil, errors.Errorf("invalid options %q, can only specify 1 '[r]bind' option", strings.Join(options, ", ")) } default: - return errors.Errorf("invalid option type %q", opt) + return nil, errors.Errorf("invalid mount option %q", opt) } + finalOpts = append(finalOpts, opt) } - return nil + return finalOpts, nil } // GetVolumeMounts takes user provided input for bind mounts and creates Mount structs @@ -633,9 +654,11 @@ func (config *CreateConfig) getVolumeMounts() (map[string]spec.Mount, map[string } if len(splitVol) > 2 { options = strings.Split(splitVol[2], ",") - if err := ValidateVolumeOpts(options); err != nil { + opts, err := ValidateVolumeOpts(options) + if err != nil { return nil, nil, err } + options = opts } if err := ValidateVolumeHostDir(src); err != nil { diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go index 489e7eeef..40c99384d 100644 --- a/pkg/util/mountOpts.go +++ b/pkg/util/mountOpts.go @@ -20,26 +20,22 @@ func ProcessOptions(options []string) []string { foundbind, foundrw, foundro bool rootProp string ) + for _, opt := range options { switch opt { case "bind", "rbind": foundbind = true - break - } - } - if !foundbind { - options = append(options, "rbind") - } - for _, opt := range options { - switch opt { - case "rw": - foundrw = true case "ro": foundro = true + case "rw": + foundrw = true case "private", "rprivate", "slave", "rslave", "shared", "rshared": rootProp = opt } } + if !foundbind { + options = append(options, "rbind") + } if !foundrw && !foundro { options = append(options, "rw") } -- cgit v1.2.3-54-g00ecf