github.com/moby/docker@v26.1.3+incompatible/internal/safepath/common.go (about) 1 package safepath 2 3 import ( 4 "os" 5 "path/filepath" 6 7 "github.com/pkg/errors" 8 ) 9 10 // evaluatePath evaluates symlinks in the concatenation of path and subpath. If 11 // err is nil, resolvedBasePath will contain result of resolving all symlinks 12 // in the given path, and resolvedSubpath will contain a relative path rooted 13 // at the resolvedBasePath pointing to the concatenation after resolving all 14 // symlinks. 15 func evaluatePath(path, subpath string) (resolvedBasePath string, resolvedSubpath string, err error) { 16 baseResolved, err := filepath.EvalSymlinks(path) 17 if err != nil { 18 if errors.Is(err, os.ErrNotExist) { 19 return "", "", &ErrNotAccessible{Path: path, Cause: err} 20 } 21 return "", "", errors.Wrapf(err, "error while resolving symlinks in base directory %q", path) 22 } 23 24 combinedPath := filepath.Join(baseResolved, subpath) 25 combinedResolved, err := filepath.EvalSymlinks(combinedPath) 26 if err != nil { 27 if errors.Is(err, os.ErrNotExist) { 28 return "", "", &ErrNotAccessible{Path: combinedPath, Cause: err} 29 } 30 return "", "", errors.Wrapf(err, "error while resolving symlinks in combined path %q", combinedPath) 31 } 32 33 subpart, err := filepath.Rel(baseResolved, combinedResolved) 34 if err != nil { 35 return "", "", &ErrEscapesBase{Base: baseResolved, Subpath: subpath} 36 } 37 38 if !filepath.IsLocal(subpart) { 39 return "", "", &ErrEscapesBase{Base: baseResolved, Subpath: subpath} 40 } 41 42 return baseResolved, subpart, nil 43 } 44 45 // isLocalTo reports whether path, using lexical analysis only, has all of these properties: 46 // - is within the subtree rooted at basepath 47 // - is not empty 48 // - on Windows, is not a reserved name such as "NUL" 49 // 50 // If isLocalTo(path, basepath) returns true, then 51 // 52 // filepath.Rel(basepath, path) 53 // 54 // will always produce an unrooted path with no `..` elements. 55 // 56 // isLocalTo is a purely lexical operation. In particular, it does not account for the effect of any symbolic links that may exist in the filesystem. 57 // 58 // Both path and basepath are expected to be absolute paths. 59 func isLocalTo(path, basepath string) bool { 60 rel, err := filepath.Rel(basepath, path) 61 if err != nil { 62 return false 63 } 64 65 return filepath.IsLocal(rel) 66 }