diff --git a/utils/fs.go b/utils/fs.go index 92864e5e16..46f64903b3 100644 --- a/utils/fs.go +++ b/utils/fs.go @@ -62,6 +62,15 @@ func FollowSymlinkInScope(link, root string) (string, error) { prev = filepath.Clean(prev) for { + if !strings.HasPrefix(prev, root) { + // Don't resolve symlinks outside of root. For example, + // we don't have to check /home in the below. + // + // /home -> usr/home + // FollowSymlinkInScope("/home/bob/foo/bar", "/home/bob/foo") + break + } + stat, err := os.Lstat(prev) if err != nil { if os.IsNotExist(err) { diff --git a/utils/fs_test.go b/utils/fs_test.go index dd5d97be40..9affc00e91 100644 --- a/utils/fs_test.go +++ b/utils/fs_test.go @@ -1,6 +1,8 @@ package utils import ( + "io/ioutil" + "os" "path/filepath" "testing" ) @@ -26,6 +28,29 @@ func TestFollowSymLinkNormal(t *testing.T) { } } +func TestFollowSymLinkUnderLinkedDir(t *testing.T) { + dir, err := ioutil.TempDir("", "docker-fs-test") + if err != nil { + t.Fatal(err) + } + + os.Mkdir(filepath.Join(dir, "realdir"), 0700) + os.Symlink("realdir", filepath.Join(dir, "linkdir")) + + linkDir := filepath.Join(dir, "linkdir", "foo") + dirUnderLinkDir := filepath.Join(dir, "linkdir", "foo", "bar") + os.MkdirAll(dirUnderLinkDir, 0700) + + rewrite, err := FollowSymlinkInScope(dirUnderLinkDir, linkDir) + if err != nil { + t.Fatal(err) + } + + if rewrite != dirUnderLinkDir { + t.Fatalf("Expected %s got %s", dirUnderLinkDir, rewrite) + } +} + func TestFollowSymLinkRandomString(t *testing.T) { if _, err := FollowSymlinkInScope("toto", "testdata"); err == nil { t.Fatal("Random string should fail but didn't")