Skip to content

Commit cafbe42

Browse files
authored
Merge pull request #138 from thaJeztah/fix_symlink_docs
symlink: touch-up documentation
2 parents 35f6c4e + 41a565e commit cafbe42

File tree

4 files changed

+68
-34
lines changed

4 files changed

+68
-34
lines changed

symlink/README.md

Lines changed: 0 additions & 6 deletions
This file was deleted.

symlink/doc.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
// Package symlink implements EvalSymlinksInScope which is an extension of
2-
// filepath.EvalSymlinks, as well as a Windows long-path aware version of
3-
// filepath.EvalSymlinks from the Go standard library (https://golang.org/pkg/path/filepath).
1+
// Package symlink implements [FollowSymlinkInScope] which is an extension
2+
// of [path/filepath.EvalSymlinks], as well as a Windows long-path aware
3+
// version of [path/filepath.EvalSymlinks] from the Go standard library.
4+
//
5+
// The code from [path/filepath.EvalSymlinks] has been adapted in fs.go.
6+
// Read the [LICENSE.BSD] file that governs fs.go and [LICENSE.APACHE] for
7+
// fs_unix_test.go.
8+
//
9+
// [LICENSE.APACHE]: https://github.com/moby/sys/blob/symlink/v0.2.0/symlink/LICENSE.APACHE
10+
// [LICENSE.BSD]: https://github.com/moby/sys/blob/symlink/v0.2.0/symlink/LICENSE.APACHE
411
package symlink

symlink/fs.go

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE.BSD file.
44

5-
// This code is a modified version of path/filepath/symlink.go from the Go standard library.
5+
// This code is a modified version of path/filepath/symlink.go from the Go
6+
// standard library in [docker@fa3ec89], which was based on [go1.3.3],
7+
// with Windows implementatinos being added in [docker@9b648df].
8+
//
9+
// [docker@fa3ec89]: https://github.com/moby/moby/commit/fa3ec89515431ce425f924c8a9a804d5cb18382f
10+
// [go1.3.3]: https://github.com/golang/go/blob/go1.3.3/src/pkg/path/filepath/symlink.go
11+
// [docker@9b648df]: https://github.com/moby/moby/commit/9b648dfac6453de5944ee4bb749115d85a253a05
612

713
package symlink
814

@@ -14,8 +20,34 @@ import (
1420
"strings"
1521
)
1622

17-
// FollowSymlinkInScope is a wrapper around evalSymlinksInScope that returns an
18-
// absolute path. This function handles paths in a platform-agnostic manner.
23+
// FollowSymlinkInScope evaluates symbolic links in "path" within a scope "root"
24+
// and returns a result guaranteed to be contained within the scope "root" at
25+
// the time of the call. It returns an error of either "path" or "root" cannot
26+
// be converted to an absolute path.
27+
//
28+
// Symbolic links in "root" are not evaluated and left as-is. Errors encountered
29+
// while attempting to evaluate symlinks in path are returned, but non-existing
30+
// paths are valid and do not constitute an error. "path" must contain "root"
31+
// as a prefix, or else an error is returned. Trying to break out from "root"
32+
// does not constitute an error, instead resolves the path within "root".
33+
//
34+
// Example:
35+
//
36+
// // If "/foo/bar" is a symbolic link to "/outside":
37+
// FollowSymlinkInScope("/foo/bar", "/foo") // Returns "/foo/outside" instead of "/outside"
38+
//
39+
// IMPORTANT: It is the caller's responsibility to call FollowSymlinkInScope
40+
// after relevant symbolic links are created to avoid Time-of-check Time-of-use
41+
// (TOCTOU) race conditions ([CWE-367]). No additional symbolic links must be
42+
// created after evaluating, as those could potentially make a previously-safe
43+
// path unsafe.
44+
//
45+
// For example, if "/foo/bar" does not exist, FollowSymlinkInScope("/foo/bar", "/foo")
46+
// evaluates the path to "/foo/bar". If one makes "/foo/bar" a symbolic link to
47+
// "/baz" subsequently, then "/foo/bar" should no longer be considered safely
48+
// contained in "/foo".
49+
//
50+
// [CWE-367]: https://cwe.mitre.org/data/definitions/367.html
1951
func FollowSymlinkInScope(path, root string) (string, error) {
2052
path, err := filepath.Abs(filepath.FromSlash(path))
2153
if err != nil {
@@ -28,24 +60,9 @@ func FollowSymlinkInScope(path, root string) (string, error) {
2860
return evalSymlinksInScope(path, root)
2961
}
3062

31-
// evalSymlinksInScope will evaluate symlinks in `path` within a scope `root` and return
32-
// a result guaranteed to be contained within the scope `root`, at the time of the call.
33-
// Symlinks in `root` are not evaluated and left as-is.
34-
// Errors encountered while attempting to evaluate symlinks in path will be returned.
35-
// Non-existing paths are valid and do not constitute an error.
36-
// `path` has to contain `root` as a prefix, or else an error will be returned.
37-
// Trying to break out from `root` does not constitute an error.
38-
//
39-
// Example:
40-
//
41-
// If /foo/bar -> /outside,
42-
// FollowSymlinkInScope("/foo/bar", "/foo") == "/foo/outside" instead of "/outside"
43-
//
44-
// IMPORTANT: it is the caller's responsibility to call evalSymlinksInScope *after* relevant symlinks
45-
// are created and not to create subsequently, additional symlinks that could potentially make a
46-
// previously-safe path, unsafe. Example: if /foo/bar does not exist, evalSymlinksInScope("/foo/bar", "/foo")
47-
// would return "/foo/bar". If one makes /foo/bar a symlink to /baz subsequently, then "/foo/bar" should
48-
// no longer be considered safely contained in "/foo".
63+
// evalSymlinksInScope evaluates symbolic links in "path" within a scope "root"
64+
// and returns a result guaranteed to be contained within the scope "root" at
65+
// the time of the call. Refer to [FollowSymlinkInScope] for details.
4966
func evalSymlinksInScope(path, root string) (string, error) {
5067
root = filepath.Clean(root)
5168
if path == root {
@@ -133,11 +150,15 @@ func evalSymlinksInScope(path, root string) (string, error) {
133150
return filepath.Clean(root + filepath.Clean(string(filepath.Separator)+b.String())), nil
134151
}
135152

153+
// EvalSymlinks is a modified version of [path/filepath.EvalSymlinks] from
154+
// the Go standard library with support for Windows long paths (paths prepended
155+
// with "\\?\"). On non-Windows platforms, it's an alias for [path/filepath.EvalSymlinks].
156+
//
136157
// EvalSymlinks returns the path name after the evaluation of any symbolic
137-
// links.
138-
// If path is relative the result will be relative to the current directory,
139-
// unless one of the components is an absolute symbolic link.
140-
// This version has been updated to support long paths prepended with `\\?\`.
158+
// links. If path is relative, the result will be relative to the current
159+
// directory, unless one of the components is an absolute symbolic link.
160+
//
161+
// EvalSymlinks calls [path/filepath.Clean] on the result.
141162
func EvalSymlinks(path string) (string, error) {
142163
return evalSymlinks(path)
143164
}

symlink/fs_windows.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
// Copyright 2012 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE.BSD file.
4+
5+
// This code is a modified version of [path/filepath/symlink_windows.go]
6+
// and [path/filepath/symlink.go] from the Go 1.4.2 standard library, and
7+
// added in [docker@9b648df].
8+
//
9+
// [path/filepath/symlink_windows.go]: https://github.com/golang/go/blob/go1.4.2/src/path/filepath/symlink_windows.go
10+
// [path/filepath/symlink.go]: https://github.com/golang/go/blob/go1.4.2/src/path/filepath/symlink.go
11+
// [docker@9b648df]: https://github.com/moby/moby/commit/9b648dfac6453de5944ee4bb749115d85a253a05
12+
113
package symlink
214

315
import (

0 commit comments

Comments
 (0)