| //go:build !windows | |
| // +build !windows | |
| package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive" | |
| import ( | |
| "io" | |
| "net" | |
| "os/user" | |
| "path/filepath" | |
| "strings" | |
| "github.com/docker/docker/pkg/archive" | |
| "github.com/pkg/errors" | |
| ) | |
| func init() { | |
| // initialize nss libraries in Glibc so that the dynamic libraries are loaded in the host | |
| // environment not in the chroot from untrusted files. | |
| _, _ = user.Lookup("docker") | |
| _, _ = net.LookupHost("localhost") | |
| } | |
| func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.TarOptions, root string) error { | |
| relDest, err := resolvePathInChroot(root, dest) | |
| if err != nil { | |
| return err | |
| } | |
| done := make(chan error) | |
| err = goInChroot(root, func() { done <- archive.Unpack(decompressedArchive, relDest, options) }) | |
| if err != nil { | |
| return err | |
| } | |
| return <-done | |
| } | |
| func invokePack(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) { | |
| relSrc, err := resolvePathInChroot(root, srcPath) | |
| if err != nil { | |
| return nil, err | |
| } | |
| // make sure we didn't trim a trailing slash with the call to `resolvePathInChroot` | |
| if strings.HasSuffix(srcPath, "/") && !strings.HasSuffix(relSrc, "/") { | |
| relSrc += "/" | |
| } | |
| tb, err := archive.NewTarballer(relSrc, options) | |
| if err != nil { | |
| return nil, errors.Wrap(err, "error processing tar file") | |
| } | |
| err = goInChroot(root, tb.Do) | |
| if err != nil { | |
| return nil, errors.Wrap(err, "could not chroot") | |
| } | |
| return tb.Reader(), nil | |
| } | |
| // resolvePathInChroot returns the equivalent to path inside a chroot rooted at root. | |
| // The returned path always begins with '/'. | |
| // | |
| // - resolvePathInChroot("/a/b", "/a/b/c/d") -> "/c/d" | |
| // - resolvePathInChroot("/a/b", "/a/b") -> "/" | |
| // | |
| // The implementation is buggy, and some bugs may be load-bearing. | |
| // Here be dragons. | |
| func resolvePathInChroot(root, path string) (string, error) { | |
| if root == "" { | |
| return "", errors.New("root path must not be empty") | |
| } | |
| rel, err := filepath.Rel(root, path) | |
| if err != nil { | |
| return "", err | |
| } | |
| if rel == "." { | |
| rel = "/" | |
| } | |
| if rel[0] != '/' { | |
| rel = "/" + rel | |
| } | |
| return rel, nil | |
| } |