123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive"
- import (
- "fmt"
- "io"
- "os"
- "path/filepath"
- "github.com/docker/docker/pkg/archive"
- "github.com/docker/docker/pkg/idtools"
- )
- // NewArchiver returns a new Archiver which uses chrootarchive.Untar
- func NewArchiver(idMapping idtools.IdentityMapping) *archive.Archiver {
- return &archive.Archiver{
- Untar: Untar,
- IDMapping: idMapping,
- }
- }
- // Untar reads a stream of bytes from `archive`, parses it as a tar archive,
- // and unpacks it into the directory at `dest`.
- // The archive may be compressed with one of the following algorithms:
- // identity (uncompressed), gzip, bzip2, xz.
- func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error {
- return untarHandler(tarArchive, dest, options, true, dest)
- }
- // UntarWithRoot is the same as `Untar`, but allows you to pass in a root directory
- // The root directory is the directory that will be chrooted to.
- // `dest` must be a path within `root`, if it is not an error will be returned.
- //
- // `root` should set to a directory which is not controlled by any potentially
- // malicious process.
- //
- // This should be used to prevent a potential attacker from manipulating `dest`
- // such that it would provide access to files outside of `dest` through things
- // like symlinks. Normally `ResolveSymlinksInScope` would handle this, however
- // sanitizing symlinks in this manner is inherrently racey:
- // ref: CVE-2018-15664
- func UntarWithRoot(tarArchive io.Reader, dest string, options *archive.TarOptions, root string) error {
- return untarHandler(tarArchive, dest, options, true, root)
- }
- // UntarUncompressed reads a stream of bytes from `archive`, parses it as a tar archive,
- // and unpacks it into the directory at `dest`.
- // The archive must be an uncompressed stream.
- func UntarUncompressed(tarArchive io.Reader, dest string, options *archive.TarOptions) error {
- return untarHandler(tarArchive, dest, options, false, dest)
- }
- // Handler for teasing out the automatic decompression
- func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions, decompress bool, root string) error {
- if tarArchive == nil {
- return fmt.Errorf("Empty archive")
- }
- if options == nil {
- options = &archive.TarOptions{}
- }
- if options.ExcludePatterns == nil {
- options.ExcludePatterns = []string{}
- }
- // If dest is inside a root then directory is created within chroot by extractor.
- // This case is only currently used by cp.
- if dest == root {
- rootIDs := options.IDMap.RootPair()
- dest = filepath.Clean(dest)
- if _, err := os.Stat(dest); os.IsNotExist(err) {
- if err := idtools.MkdirAllAndChownNew(dest, 0o755, rootIDs); err != nil {
- return err
- }
- }
- }
- r := io.NopCloser(tarArchive)
- if decompress {
- decompressedArchive, err := archive.DecompressStream(tarArchive)
- if err != nil {
- return err
- }
- defer decompressedArchive.Close()
- r = decompressedArchive
- }
- return invokeUnpack(r, dest, options, root)
- }
- // Tar tars the requested path while chrooted to the specified root.
- func Tar(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) {
- if options == nil {
- options = &archive.TarOptions{}
- }
- return invokePack(srcPath, options, root)
- }
|