archive.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive"
  2. import (
  3. "fmt"
  4. "io"
  5. "net"
  6. "os"
  7. "os/user"
  8. "path/filepath"
  9. "github.com/docker/docker/pkg/archive"
  10. "github.com/docker/docker/pkg/idtools"
  11. )
  12. func init() {
  13. // initialize nss libraries in Glibc so that the dynamic libraries are loaded in the host
  14. // environment not in the chroot from untrusted files.
  15. _, _ = user.Lookup("docker")
  16. _, _ = net.LookupHost("localhost")
  17. }
  18. // NewArchiver returns a new Archiver which uses chrootarchive.Untar
  19. func NewArchiver(idMapping idtools.IdentityMapping) *archive.Archiver {
  20. return &archive.Archiver{
  21. Untar: Untar,
  22. IDMapping: idMapping,
  23. }
  24. }
  25. // Untar reads a stream of bytes from `archive`, parses it as a tar archive,
  26. // and unpacks it into the directory at `dest`.
  27. // The archive may be compressed with one of the following algorithms:
  28. // identity (uncompressed), gzip, bzip2, xz.
  29. func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error {
  30. return untarHandler(tarArchive, dest, options, true, dest)
  31. }
  32. // UntarWithRoot is the same as `Untar`, but allows you to pass in a root directory
  33. // The root directory is the directory that will be chrooted to.
  34. // `dest` must be a path within `root`, if it is not an error will be returned.
  35. //
  36. // `root` should set to a directory which is not controlled by any potentially
  37. // malicious process.
  38. //
  39. // This should be used to prevent a potential attacker from manipulating `dest`
  40. // such that it would provide access to files outside of `dest` through things
  41. // like symlinks. Normally `ResolveSymlinksInScope` would handle this, however
  42. // sanitizing symlinks in this manner is inherrently racey:
  43. // ref: CVE-2018-15664
  44. func UntarWithRoot(tarArchive io.Reader, dest string, options *archive.TarOptions, root string) error {
  45. return untarHandler(tarArchive, dest, options, true, root)
  46. }
  47. // UntarUncompressed reads a stream of bytes from `archive`, parses it as a tar archive,
  48. // and unpacks it into the directory at `dest`.
  49. // The archive must be an uncompressed stream.
  50. func UntarUncompressed(tarArchive io.Reader, dest string, options *archive.TarOptions) error {
  51. return untarHandler(tarArchive, dest, options, false, dest)
  52. }
  53. // Handler for teasing out the automatic decompression
  54. func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions, decompress bool, root string) error {
  55. if tarArchive == nil {
  56. return fmt.Errorf("Empty archive")
  57. }
  58. if options == nil {
  59. options = &archive.TarOptions{}
  60. }
  61. if options.ExcludePatterns == nil {
  62. options.ExcludePatterns = []string{}
  63. }
  64. // If dest is inside a root then directory is created within chroot by extractor.
  65. // This case is only currently used by cp.
  66. if dest == root {
  67. rootIDs := options.IDMap.RootPair()
  68. dest = filepath.Clean(dest)
  69. if _, err := os.Stat(dest); os.IsNotExist(err) {
  70. if err := idtools.MkdirAllAndChownNew(dest, 0755, rootIDs); err != nil {
  71. return err
  72. }
  73. }
  74. }
  75. r := io.NopCloser(tarArchive)
  76. if decompress {
  77. decompressedArchive, err := archive.DecompressStream(tarArchive)
  78. if err != nil {
  79. return err
  80. }
  81. defer decompressedArchive.Close()
  82. r = decompressedArchive
  83. }
  84. return invokeUnpack(r, dest, options, root)
  85. }
  86. // Tar tars the requested path while chrooted to the specified root.
  87. func Tar(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) {
  88. if options == nil {
  89. options = &archive.TarOptions{}
  90. }
  91. return invokePack(srcPath, options, root)
  92. }