Clean destination paths during mount generation

We identify and resolve conflicts in paths using destination path
matches. We require exact matches, largely for performance
reasons (we use maps to efficiently access, keyed by
destination). This usually works fine, until you get mounts that
are targetted at /output and /output/ - the same path, but not
the same string.

Use filepath.Clean() aggressively to try and solve this.

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
This commit is contained in:
Matthew Heon
2019-09-19 11:09:59 -04:00
parent 408f2780a1
commit 720d8c9e3f

View File

@ -220,6 +220,7 @@ func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount,
// volumes, and return a list of them. // volumes, and return a list of them.
// Conflicts are resolved simply - the last container specified wins. // Conflicts are resolved simply - the last container specified wins.
// Container names may be suffixed by mount options after a colon. // Container names may be suffixed by mount options after a colon.
// TODO: We should clean these paths if possible
func (config *CreateConfig) getVolumesFrom(runtime *libpod.Runtime) (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) { func (config *CreateConfig) getVolumesFrom(runtime *libpod.Runtime) (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) {
// Both of these are maps of mount destination to mount type. // Both of these are maps of mount destination to mount type.
// We ensure that each destination is only mounted to once in this way. // We ensure that each destination is only mounted to once in this way.
@ -465,7 +466,7 @@ func getBindMount(args []string) (spec.Mount, error) {
if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil { if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
return newMount, err return newMount, err
} }
newMount.Destination = kv[1] newMount.Destination = filepath.Clean(kv[1])
setDest = true setDest = true
case "relabel": case "relabel":
if setRelabel { if setRelabel {
@ -559,7 +560,7 @@ func getTmpfsMount(args []string) (spec.Mount, error) {
if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil { if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
return newMount, err return newMount, err
} }
newMount.Destination = kv[1] newMount.Destination = filepath.Clean(kv[1])
setDest = true setDest = true
default: default:
return newMount, errors.Wrapf(util.ErrBadMntOption, kv[0]) return newMount, errors.Wrapf(util.ErrBadMntOption, kv[0])
@ -623,7 +624,7 @@ func getNamedVolume(args []string) (*libpod.ContainerNamedVolume, error) {
if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil { if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
return nil, err return nil, err
} }
newVolume.Dest = kv[1] newVolume.Dest = filepath.Clean(kv[1])
setDest = true setDest = true
default: default:
return nil, errors.Wrapf(util.ErrBadMntOption, kv[0]) return nil, errors.Wrapf(util.ErrBadMntOption, kv[0])
@ -678,10 +679,12 @@ func (config *CreateConfig) getVolumeMounts() (map[string]spec.Mount, map[string
return nil, nil, err return nil, nil, err
} }
cleanDest := filepath.Clean(dest)
if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") { if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") {
// This is not a named volume // This is not a named volume
newMount := spec.Mount{ newMount := spec.Mount{
Destination: dest, Destination: cleanDest,
Type: string(TypeBind), Type: string(TypeBind),
Source: src, Source: src,
Options: options, Options: options,
@ -694,7 +697,7 @@ func (config *CreateConfig) getVolumeMounts() (map[string]spec.Mount, map[string
// This is a named volume // This is a named volume
newNamedVol := new(libpod.ContainerNamedVolume) newNamedVol := new(libpod.ContainerNamedVolume)
newNamedVol.Name = src newNamedVol.Name = src
newNamedVol.Dest = dest newNamedVol.Dest = cleanDest
newNamedVol.Options = options newNamedVol.Options = options
if _, ok := volumes[newNamedVol.Dest]; ok { if _, ok := volumes[newNamedVol.Dest]; ok {
@ -719,10 +722,11 @@ func (config *CreateConfig) getImageVolumes() (map[string]spec.Mount, map[string
} }
for vol := range config.BuiltinImgVolumes { for vol := range config.BuiltinImgVolumes {
cleanDest := filepath.Clean(vol)
if config.ImageVolumeType == "tmpfs" { if config.ImageVolumeType == "tmpfs" {
// Tmpfs image volumes are handled as mounts // Tmpfs image volumes are handled as mounts
mount := spec.Mount{ mount := spec.Mount{
Destination: vol, Destination: cleanDest,
Source: TypeTmpfs, Source: TypeTmpfs,
Type: TypeTmpfs, Type: TypeTmpfs,
Options: []string{"rprivate", "rw", "nodev"}, Options: []string{"rprivate", "rw", "nodev"},
@ -732,7 +736,7 @@ func (config *CreateConfig) getImageVolumes() (map[string]spec.Mount, map[string
namedVolume := new(libpod.ContainerNamedVolume) namedVolume := new(libpod.ContainerNamedVolume)
namedVolume.Name = stringid.GenerateNonCryptoID() namedVolume.Name = stringid.GenerateNonCryptoID()
namedVolume.Options = []string{"rprivate", "rw", "nodev"} namedVolume.Options = []string{"rprivate", "rw", "nodev"}
namedVolume.Dest = vol namedVolume.Dest = cleanDest
volumes[vol] = namedVolume volumes[vol] = namedVolume
} }
} }
@ -760,7 +764,7 @@ func (config *CreateConfig) getTmpfsMounts() (map[string]spec.Mount, error) {
} }
mount := spec.Mount{ mount := spec.Mount{
Destination: destPath, Destination: filepath.Clean(destPath),
Type: string(TypeTmpfs), Type: string(TypeTmpfs),
Options: options, Options: options,
Source: string(TypeTmpfs), Source: string(TypeTmpfs),