1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
//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
}
|