//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 }