From 7cb96ba308dc53824d2203fd343a4a297d17976e Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 19 Dec 2017 11:44:29 +0100 Subject: [PATCH] Re-validate Mounts on container start Validation of Mounts was only performed on container _creation_, not on container _start_. As a result, if the host-path no longer existed when the container was started, a directory was created in the given location. This is the wrong behavior, because when using the `Mounts` API, host paths should never be created, and an error should be produced instead. This patch adds a validation step on container start, and produces an error if the host path is not found. Signed-off-by: Sebastiaan van Stijn --- daemon/container.go | 9 +++++++++ volume/lcow_parser.go | 2 +- volume/linux_parser.go | 2 +- volume/parser.go | 3 +-- volume/validate_test.go | 12 ++++-------- volume/windows_parser.go | 2 +- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/daemon/container.go b/daemon/container.go index 26faedfdf9..b2f4f1053f 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -19,6 +19,7 @@ import ( "github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/truncindex" "github.com/docker/docker/runconfig" + "github.com/docker/docker/volume" "github.com/docker/go-connections/nat" "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" @@ -293,6 +294,14 @@ func (daemon *Daemon) verifyContainerSettings(platform string, hostConfig *conta return nil, errors.Errorf("can't create 'AutoRemove' container with restart policy") } + // Validate mounts; check if host directories still exist + parser := volume.NewParser(platform) + for _, cfg := range hostConfig.Mounts { + if err := parser.ValidateMountConfig(&cfg); err != nil { + return nil, err + } + } + for _, extraHost := range hostConfig.ExtraHosts { if _, err := opts.ValidateExtraHost(extraHost); err != nil { return nil, err diff --git a/volume/lcow_parser.go b/volume/lcow_parser.go index aeb81a4202..8d15f0d9d7 100644 --- a/volume/lcow_parser.go +++ b/volume/lcow_parser.go @@ -22,7 +22,7 @@ type lcowParser struct { windowsParser } -func (p *lcowParser) validateMountConfig(mnt *mount.Mount) error { +func (p *lcowParser) ValidateMountConfig(mnt *mount.Mount) error { return p.validateMountConfigReg(mnt, rxLCOWDestination, lcowSpecificValidators) } diff --git a/volume/linux_parser.go b/volume/linux_parser.go index 59605fe677..fd54e82162 100644 --- a/volume/linux_parser.go +++ b/volume/linux_parser.go @@ -40,7 +40,7 @@ func linuxValidateAbsolute(p string) error { } return fmt.Errorf("invalid mount path: '%s' mount path must be absolute", p) } -func (p *linuxParser) validateMountConfig(mnt *mount.Mount) error { +func (p *linuxParser) ValidateMountConfig(mnt *mount.Mount) error { // there was something looking like a bug in existing codebase: // - validateMountConfig on linux was called with options skipping bind source existence when calling ParseMountRaw // - but not when calling ParseMountSpec directly... nor when the unit test called it directly diff --git a/volume/parser.go b/volume/parser.go index 1f48b60e27..13fd7d1489 100644 --- a/volume/parser.go +++ b/volume/parser.go @@ -26,8 +26,7 @@ type Parser interface { IsBackwardCompatible(m *MountPoint) bool HasResource(m *MountPoint, absPath string) bool ValidateTmpfsMountDestination(dest string) error - - validateMountConfig(mt *mount.Mount) error + ValidateMountConfig(mt *mount.Mount) error } // NewParser creates a parser for a given container OS, depending on the current host OS (linux on a windows host will resolve to an lcowParser) diff --git a/volume/validate_test.go b/volume/validate_test.go index 6a8e28682b..eac343f50a 100644 --- a/volume/validate_test.go +++ b/volume/validate_test.go @@ -31,13 +31,9 @@ func TestValidateMount(t *testing.T) { {mount.Mount{Type: mount.TypeBind, Source: testDir, Target: testDestinationPath}, nil}, {mount.Mount{Type: "invalid", Target: testDestinationPath}, errors.New("mount type unknown")}, + {mount.Mount{Type: mount.TypeBind, Source: testSourcePath, Target: testDestinationPath}, errBindNotExist}, } - if runtime.GOOS == "windows" { - cases = append(cases, struct { - input mount.Mount - expected error - }{mount.Mount{Type: mount.TypeBind, Source: testSourcePath, Target: testDestinationPath}, errBindNotExist}) // bind source existance is not checked on linux - } + lcowCases := []struct { input mount.Mount expected error @@ -54,7 +50,7 @@ func TestValidateMount(t *testing.T) { } parser := NewParser(runtime.GOOS) for i, x := range cases { - err := parser.validateMountConfig(&x.input) + err := parser.ValidateMountConfig(&x.input) if err == nil && x.expected == nil { continue } @@ -65,7 +61,7 @@ func TestValidateMount(t *testing.T) { if runtime.GOOS == "windows" { parser = &lcowParser{} for i, x := range lcowCases { - err := parser.validateMountConfig(&x.input) + err := parser.ValidateMountConfig(&x.input) if err == nil && x.expected == nil { continue } diff --git a/volume/windows_parser.go b/volume/windows_parser.go index 172610dbdd..5cf1a8da74 100644 --- a/volume/windows_parser.go +++ b/volume/windows_parser.go @@ -189,7 +189,7 @@ func (p *windowsParser) ValidateVolumeName(name string) error { } return nil } -func (p *windowsParser) validateMountConfig(mnt *mount.Mount) error { +func (p *windowsParser) ValidateMountConfig(mnt *mount.Mount) error { return p.validateMountConfigReg(mnt, rxDestination, windowsSpecificValidators) }