archive_unix.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. //go:build !windows
  2. // +build !windows
  3. package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive"
  4. import (
  5. "io"
  6. "net"
  7. "os/user"
  8. "path/filepath"
  9. "strings"
  10. "github.com/docker/docker/pkg/archive"
  11. "github.com/pkg/errors"
  12. )
  13. func init() {
  14. // initialize nss libraries in Glibc so that the dynamic libraries are loaded in the host
  15. // environment not in the chroot from untrusted files.
  16. _, _ = user.Lookup("docker")
  17. _, _ = net.LookupHost("localhost")
  18. }
  19. func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.TarOptions, root string) error {
  20. relDest, err := resolvePathInChroot(root, dest)
  21. if err != nil {
  22. return err
  23. }
  24. done := make(chan error)
  25. err = goInChroot(root, func() { done <- archive.Unpack(decompressedArchive, relDest, options) })
  26. if err != nil {
  27. return err
  28. }
  29. return <-done
  30. }
  31. func invokePack(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) {
  32. relSrc, err := resolvePathInChroot(root, srcPath)
  33. if err != nil {
  34. return nil, err
  35. }
  36. // make sure we didn't trim a trailing slash with the call to `resolvePathInChroot`
  37. if strings.HasSuffix(srcPath, "/") && !strings.HasSuffix(relSrc, "/") {
  38. relSrc += "/"
  39. }
  40. tb, err := archive.NewTarballer(relSrc, options)
  41. if err != nil {
  42. return nil, errors.Wrap(err, "error processing tar file")
  43. }
  44. err = goInChroot(root, tb.Do)
  45. if err != nil {
  46. return nil, errors.Wrap(err, "could not chroot")
  47. }
  48. return tb.Reader(), nil
  49. }
  50. // resolvePathInChroot returns the equivalent to path inside a chroot rooted at root.
  51. // The returned path always begins with '/'.
  52. //
  53. // - resolvePathInChroot("/a/b", "/a/b/c/d") -> "/c/d"
  54. // - resolvePathInChroot("/a/b", "/a/b") -> "/"
  55. //
  56. // The implementation is buggy, and some bugs may be load-bearing.
  57. // Here be dragons.
  58. func resolvePathInChroot(root, path string) (string, error) {
  59. if root == "" {
  60. return "", errors.New("root path must not be empty")
  61. }
  62. rel, err := filepath.Rel(root, path)
  63. if err != nil {
  64. return "", err
  65. }
  66. if rel == "." {
  67. rel = "/"
  68. }
  69. if rel[0] != '/' {
  70. rel = "/" + rel
  71. }
  72. return rel, nil
  73. }