From 020ec43b5619d22ccea83ff59ecbb6c2191ecee4 Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Thu, 6 Jul 2017 17:46:17 +0100 Subject: [PATCH] Fix subPath existence check to not follow symlink Volume mounting logic introduced in #43775 and #45623 checks for subPath existence before attempting to create a directory, should subPath not be present. This breaks if subPath is a dangling symlink, os.Stat returns "do not exist" status, yet `os.MkdirAll` can't create directory as symlink is present at the given path. This patch makes existence check to use os.Lstat which works for normal files/directories as well as doesn't not attempt to follow symlink, therefore it's "do not exist" status is more reliable when making a decision whether to create directory or not. subPath symlinks can be dangling in situations where kubelet is running in a container itself with access to docker socket, such as CoreOS's kubelet-wrapper script --- pkg/kubelet/kubelet_pods.go | 2 +- pkg/util/util.go | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/kubelet/kubelet_pods.go b/pkg/kubelet/kubelet_pods.go index e4c1aa5738..01d89bd334 100644 --- a/pkg/kubelet/kubelet_pods.go +++ b/pkg/kubelet/kubelet_pods.go @@ -146,7 +146,7 @@ func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, h hostPath = filepath.Join(hostPath, mount.SubPath) - if subPathExists, err := util.FileExists(hostPath); err != nil { + if subPathExists, err := util.FileOrSymlinkExists(hostPath); err != nil { glog.Errorf("Could not determine if subPath %s exists; will not attempt to change its permissions", hostPath) } else if !subPathExists { // Create the sub path now because if it's auto-created later when referenced, it may have an diff --git a/pkg/util/util.go b/pkg/util/util.go index 356b295a3e..389e145e84 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -84,6 +84,15 @@ func FileExists(filename string) (bool, error) { return true, nil } +func FileOrSymlinkExists(filename string) (bool, error) { + if _, err := os.Lstat(filename); os.IsNotExist(err) { + return false, nil + } else if err != nil { + return false, err + } + return true, nil +} + // ReadDirNoStat returns a string of files/directories contained // in dirname without calling lstat on them. func ReadDirNoStat(dirname string) ([]string, error) {