diff --git a/builder/dockerfile/internals_linux.go b/builder/dockerfile/internals_linux.go index 5dbd86f147..269f722d61 100644 --- a/builder/dockerfile/internals_linux.go +++ b/builder/dockerfile/internals_linux.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/docker/docker/pkg/idtools" - "github.com/docker/docker/pkg/symlink" + "github.com/moby/sys/symlink" lcUser "github.com/opencontainers/runc/libcontainer/user" "github.com/pkg/errors" ) diff --git a/builder/remotecontext/git/gitutils.go b/builder/remotecontext/git/gitutils.go index ffd5123798..b3aba7f58b 100644 --- a/builder/remotecontext/git/gitutils.go +++ b/builder/remotecontext/git/gitutils.go @@ -9,7 +9,7 @@ import ( "path/filepath" "strings" - "github.com/docker/docker/pkg/symlink" + "github.com/moby/sys/symlink" "github.com/pkg/errors" ) diff --git a/container/container.go b/container/container.go index 5610c9b431..df90a4ee2c 100644 --- a/container/container.go +++ b/container/container.go @@ -32,13 +32,13 @@ import ( "github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/signal" - "github.com/docker/docker/pkg/symlink" "github.com/docker/docker/pkg/system" "github.com/docker/docker/restartmanager" "github.com/docker/docker/volume" volumemounts "github.com/docker/docker/volume/mounts" units "github.com/docker/go-units" agentexec "github.com/docker/swarmkit/agent/exec" + "github.com/moby/sys/symlink" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) diff --git a/image/tarexport/load.go b/image/tarexport/load.go index cc22127038..bbbb238b2b 100644 --- a/image/tarexport/load.go +++ b/image/tarexport/load.go @@ -22,8 +22,8 @@ import ( "github.com/docker/docker/pkg/progress" "github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/pkg/stringid" - "github.com/docker/docker/pkg/symlink" "github.com/docker/docker/pkg/system" + "github.com/moby/sys/symlink" digest "github.com/opencontainers/go-digest" "github.com/sirupsen/logrus" ) diff --git a/pkg/containerfs/containerfs.go b/pkg/containerfs/containerfs.go index 7bb1d8c369..d25826ddbb 100644 --- a/pkg/containerfs/containerfs.go +++ b/pkg/containerfs/containerfs.go @@ -6,7 +6,7 @@ import ( "github.com/containerd/continuity/driver" "github.com/containerd/continuity/pathdriver" - "github.com/docker/docker/pkg/symlink" + "github.com/moby/sys/symlink" ) // ContainerFS is that represents a root file system diff --git a/pkg/symlink/deprecated.go b/pkg/symlink/deprecated.go new file mode 100644 index 0000000000..c4f12ef218 --- /dev/null +++ b/pkg/symlink/deprecated.go @@ -0,0 +1,12 @@ +package symlink // import "github.com/docker/docker/pkg/symlink" + +import "github.com/moby/sys/symlink" + +var ( + // EvalSymlinks is deprecated and moved to github.com/moby/sys/symlink + // Deprecated: use github.com/moby/sys/symlink.EvalSymlinks instead + EvalSymlinks = symlink.EvalSymlinks + // FollowSymlinkInScope is deprecated and moved to github.com/moby/sys/symlink + // Deprecated: use github.com/moby/sys/symlink.FollowSymlinkInScope instead + FollowSymlinkInScope = symlink.FollowSymlinkInScope +) diff --git a/pkg/symlink/fs_unix_test.go b/pkg/symlink/fs_unix_test.go deleted file mode 100644 index 9ed1dd70db..0000000000 --- a/pkg/symlink/fs_unix_test.go +++ /dev/null @@ -1,407 +0,0 @@ -// +build !windows - -// Licensed under the Apache License, Version 2.0; See LICENSE.APACHE - -package symlink // import "github.com/docker/docker/pkg/symlink" - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "testing" -) - -// TODO Windows: This needs some serious work to port to Windows. For now, -// turning off testing in this package. - -type dirOrLink struct { - path string - target string -} - -func makeFs(tmpdir string, fs []dirOrLink) error { - for _, s := range fs { - s.path = filepath.Join(tmpdir, s.path) - if s.target == "" { - os.MkdirAll(s.path, 0755) - continue - } - if err := os.MkdirAll(filepath.Dir(s.path), 0755); err != nil { - return err - } - if err := os.Symlink(s.target, s.path); err != nil && !os.IsExist(err) { - return err - } - } - return nil -} - -func testSymlink(tmpdir, path, expected, scope string) error { - rewrite, err := FollowSymlinkInScope(filepath.Join(tmpdir, path), filepath.Join(tmpdir, scope)) - if err != nil { - return err - } - expected, err = filepath.Abs(filepath.Join(tmpdir, expected)) - if err != nil { - return err - } - if expected != rewrite { - return fmt.Errorf("Expected %q got %q", expected, rewrite) - } - return nil -} - -func TestFollowSymlinkAbsolute(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkAbsolute") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - if err := makeFs(tmpdir, []dirOrLink{{path: "testdata/fs/a/d", target: "/b"}}); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "testdata/fs/a/d/c/data", "testdata/b/c/data", "testdata"); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkRelativePath(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkRelativePath") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - if err := makeFs(tmpdir, []dirOrLink{{path: "testdata/fs/i", target: "a"}}); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "testdata/fs/i", "testdata/fs/a", "testdata"); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkSkipSymlinksOutsideScope(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkSkipSymlinksOutsideScope") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - if err := makeFs(tmpdir, []dirOrLink{ - {path: "linkdir", target: "realdir"}, - {path: "linkdir/foo/bar"}, - }); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "linkdir/foo/bar", "linkdir/foo/bar", "linkdir/foo"); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkInvalidScopePathPair(t *testing.T) { - if _, err := FollowSymlinkInScope("toto", "testdata"); err == nil { - t.Fatal("expected an error") - } -} - -func TestFollowSymlinkLastLink(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkLastLink") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - if err := makeFs(tmpdir, []dirOrLink{{path: "testdata/fs/a/d", target: "/b"}}); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "testdata/fs/a/d", "testdata/b", "testdata"); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkRelativeLinkChangeScope(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkRelativeLinkChangeScope") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - if err := makeFs(tmpdir, []dirOrLink{{path: "testdata/fs/a/e", target: "../b"}}); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "testdata/fs/a/e/c/data", "testdata/fs/b/c/data", "testdata"); err != nil { - t.Fatal(err) - } - // avoid letting allowing symlink e lead us to ../b - // normalize to the "testdata/fs/a" - if err := testSymlink(tmpdir, "testdata/fs/a/e", "testdata/fs/a/b", "testdata/fs/a"); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkDeepRelativeLinkChangeScope(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkDeepRelativeLinkChangeScope") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - if err := makeFs(tmpdir, []dirOrLink{{path: "testdata/fs/a/f", target: "../../../../test"}}); err != nil { - t.Fatal(err) - } - // avoid letting symlink f lead us out of the "testdata" scope - // we don't normalize because symlink f is in scope and there is no - // information leak - if err := testSymlink(tmpdir, "testdata/fs/a/f", "testdata/test", "testdata"); err != nil { - t.Fatal(err) - } - // avoid letting symlink f lead us out of the "testdata/fs" scope - // we don't normalize because symlink f is in scope and there is no - // information leak - if err := testSymlink(tmpdir, "testdata/fs/a/f", "testdata/fs/test", "testdata/fs"); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkRelativeLinkChain(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkRelativeLinkChain") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - // avoid letting symlink g (pointed at by symlink h) take out of scope - // TODO: we should probably normalize to scope here because ../[....]/root - // is out of scope and we leak information - if err := makeFs(tmpdir, []dirOrLink{ - {path: "testdata/fs/b/h", target: "../g"}, - {path: "testdata/fs/g", target: "../../../../../../../../../../../../root"}, - }); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "testdata/fs/b/h", "testdata/root", "testdata"); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkBreakoutPath(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkBreakoutPath") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - // avoid letting symlink -> ../directory/file escape from scope - // normalize to "testdata/fs/j" - if err := makeFs(tmpdir, []dirOrLink{{path: "testdata/fs/j/k", target: "../i/a"}}); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "testdata/fs/j/k", "testdata/fs/j/i/a", "testdata/fs/j"); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkToRoot(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkToRoot") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - // make sure we don't allow escaping to / - // normalize to dir - if err := makeFs(tmpdir, []dirOrLink{{path: "foo", target: "/"}}); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "foo", "", ""); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkSlashDotdot(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkSlashDotdot") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - tmpdir = filepath.Join(tmpdir, "dir", "subdir") - - // make sure we don't allow escaping to / - // normalize to dir - if err := makeFs(tmpdir, []dirOrLink{{path: "foo", target: "/../../"}}); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "foo", "", ""); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkDotdot(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkDotdot") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - tmpdir = filepath.Join(tmpdir, "dir", "subdir") - - // make sure we stay in scope without leaking information - // this also checks for escaping to / - // normalize to dir - if err := makeFs(tmpdir, []dirOrLink{{path: "foo", target: "../../"}}); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "foo", "", ""); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkRelativePath2(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkRelativePath2") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - if err := makeFs(tmpdir, []dirOrLink{{path: "bar/foo", target: "baz/target"}}); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "bar/foo", "bar/baz/target", ""); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkScopeLink(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkScopeLink") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - if err := makeFs(tmpdir, []dirOrLink{ - {path: "root2"}, - {path: "root", target: "root2"}, - {path: "root2/foo", target: "../bar"}, - }); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "root/foo", "root/bar", "root"); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkRootScope(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkRootScope") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - expected, err := filepath.EvalSymlinks(tmpdir) - if err != nil { - t.Fatal(err) - } - rewrite, err := FollowSymlinkInScope(tmpdir, "/") - if err != nil { - t.Fatal(err) - } - if rewrite != expected { - t.Fatalf("expected %q got %q", expected, rewrite) - } -} - -func TestFollowSymlinkEmpty(t *testing.T) { - res, err := FollowSymlinkInScope("", "") - if err != nil { - t.Fatal(err) - } - wd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - if res != wd { - t.Fatalf("expected %q got %q", wd, res) - } -} - -func TestFollowSymlinkCircular(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkCircular") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - if err := makeFs(tmpdir, []dirOrLink{{path: "root/foo", target: "foo"}}); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "root/foo", "", "root"); err == nil { - t.Fatal("expected an error for foo -> foo") - } - - if err := makeFs(tmpdir, []dirOrLink{ - {path: "root/bar", target: "baz"}, - {path: "root/baz", target: "../bak"}, - {path: "root/bak", target: "/bar"}, - }); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "root/foo", "", "root"); err == nil { - t.Fatal("expected an error for bar -> baz -> bak -> bar") - } -} - -func TestFollowSymlinkComplexChainWithTargetPathsContainingLinks(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkComplexChainWithTargetPathsContainingLinks") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - if err := makeFs(tmpdir, []dirOrLink{ - {path: "root2"}, - {path: "root", target: "root2"}, - {path: "root/a", target: "r/s"}, - {path: "root/r", target: "../root/t"}, - {path: "root/root/t/s/b", target: "/../u"}, - {path: "root/u/c", target: "."}, - {path: "root/u/x/y", target: "../v"}, - {path: "root/u/v", target: "/../w"}, - }); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "root/a/b/c/x/y/z", "root/w/z", "root"); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkBreakoutNonExistent(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkBreakoutNonExistent") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - if err := makeFs(tmpdir, []dirOrLink{ - {path: "root/slash", target: "/"}, - {path: "root/sym", target: "/idontexist/../slash"}, - }); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "root/sym/file", "root/file", "root"); err != nil { - t.Fatal(err) - } -} - -func TestFollowSymlinkNoLexicalCleaning(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkNoLexicalCleaning") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - if err := makeFs(tmpdir, []dirOrLink{ - {path: "root/sym", target: "/foo/bar"}, - {path: "root/hello", target: "/sym/../baz"}, - }); err != nil { - t.Fatal(err) - } - if err := testSymlink(tmpdir, "root/hello", "root/foo/baz", "root"); err != nil { - t.Fatal(err) - } -} diff --git a/vendor.conf b/vendor.conf index c4bcf0b447..b2b058804f 100644 --- a/vendor.conf +++ b/vendor.conf @@ -9,12 +9,12 @@ github.com/Microsoft/opengcs a10967154e143a36014584a6f664 github.com/moby/locker 281af2d563954745bea9d1487c965f24d30742fe # v1.0.1 github.com/moby/term 7f0af18e79f2784809e9cef63d0df5aa2c79d76e -# Note that this dependency uses submodules, providing the github.com/moby/sys/mount -# and github.com/moby/sys/mountinfo modules. Our vendoring tool (vndr) currently -# does not support submodules / vendoring sub-paths, so we vendor the top-level -# moby/sys repository (which contains both) and pick the most recent tag, which -# could be either `mountinfo/vX.Y.Z` or `mount/vX.Y.Z`. -github.com/moby/sys 9a75fe61baf4b9788826b48b0518abecffb79b16 # mountinfo v0.4.0 +# Note that this dependency uses submodules, providing the github.com/moby/sys/mount, +# github.com/moby/sys/mountinfo, and github.com/moby/sys/symlink modules. Our vendoring +# tool (vndr) currently does not support submodules / vendoring sub-paths, so we vendor +# the top-level moby/sys repository (which contains both) and pick the most recent tag, +# which could be either `mountinfo/vX.Y.Z`, `mount/vX.Y.Z`, or `symlink/vX.Y.Z`. +github.com/moby/sys 1bc8673b57550ddf85262eb0fed0aac651a37dab # symlink/v0.1.0 github.com/creack/pty 3a6a957789163cacdfe0e291617a1c8e80612c11 # v1.1.9 github.com/sirupsen/logrus 6699a89a232f3db797f2e280639854bbc4b89725 # v1.7.0 diff --git a/pkg/symlink/LICENSE.APACHE b/vendor/github.com/moby/sys/symlink/LICENSE.APACHE similarity index 100% rename from pkg/symlink/LICENSE.APACHE rename to vendor/github.com/moby/sys/symlink/LICENSE.APACHE diff --git a/pkg/symlink/LICENSE.BSD b/vendor/github.com/moby/sys/symlink/LICENSE.BSD similarity index 100% rename from pkg/symlink/LICENSE.BSD rename to vendor/github.com/moby/sys/symlink/LICENSE.BSD diff --git a/pkg/symlink/README.md b/vendor/github.com/moby/sys/symlink/README.md similarity index 100% rename from pkg/symlink/README.md rename to vendor/github.com/moby/sys/symlink/README.md diff --git a/vendor/github.com/moby/sys/symlink/doc.go b/vendor/github.com/moby/sys/symlink/doc.go new file mode 100644 index 0000000000..d2de7ecda0 --- /dev/null +++ b/vendor/github.com/moby/sys/symlink/doc.go @@ -0,0 +1,4 @@ +// Package symlink implements EvalSymlinksInScope which is an extension of +// filepath.EvalSymlinks, as well as a Windows long-path aware version of +// filepath.EvalSymlinks from the Go standard library (https://golang.org/pkg/path/filepath). +package symlink diff --git a/pkg/symlink/fs.go b/vendor/github.com/moby/sys/symlink/fs.go similarity index 98% rename from pkg/symlink/fs.go rename to vendor/github.com/moby/sys/symlink/fs.go index fb8b77ffaa..244b0096b9 100644 --- a/pkg/symlink/fs.go +++ b/vendor/github.com/moby/sys/symlink/fs.go @@ -4,7 +4,7 @@ // This code is a modified version of path/filepath/symlink.go from the Go standard library. -package symlink // import "github.com/docker/docker/pkg/symlink" +package symlink import ( "bytes" diff --git a/pkg/symlink/fs_unix.go b/vendor/github.com/moby/sys/symlink/fs_unix.go similarity index 78% rename from pkg/symlink/fs_unix.go rename to vendor/github.com/moby/sys/symlink/fs_unix.go index 855fda5abc..ef960a0879 100644 --- a/pkg/symlink/fs_unix.go +++ b/vendor/github.com/moby/sys/symlink/fs_unix.go @@ -1,6 +1,6 @@ // +build !windows -package symlink // import "github.com/docker/docker/pkg/symlink" +package symlink import ( "path/filepath" diff --git a/pkg/symlink/fs_windows.go b/vendor/github.com/moby/sys/symlink/fs_windows.go similarity index 98% rename from pkg/symlink/fs_windows.go rename to vendor/github.com/moby/sys/symlink/fs_windows.go index 495518f698..7603fafa68 100644 --- a/pkg/symlink/fs_windows.go +++ b/vendor/github.com/moby/sys/symlink/fs_windows.go @@ -1,4 +1,4 @@ -package symlink // import "github.com/docker/docker/pkg/symlink" +package symlink import ( "bytes" diff --git a/vendor/github.com/moby/sys/symlink/go.mod b/vendor/github.com/moby/sys/symlink/go.mod new file mode 100644 index 0000000000..6383f091e9 --- /dev/null +++ b/vendor/github.com/moby/sys/symlink/go.mod @@ -0,0 +1,5 @@ +module github.com/moby/sys/symlink + +go 1.13 + +require golang.org/x/sys v0.0.0-20200922070232-aee5d888a860