mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
80f1169eca
If chroot is used with a special root directory then create destination directory within chroot. This works automatically already due to extractor creating parent paths and is only used currently with cp where parent paths are actually required and error will be shown to user before reaching this point. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com> (cherry picked from commit 52d285184068998c22632bfb869f6294b5613a58) Signed-off-by: Brian Goff <cpuguy83@gmail.com>
110 lines
3.6 KiB
Go
110 lines
3.6 KiB
Go
package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive"
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net"
|
|
"os"
|
|
"os/user"
|
|
"path/filepath"
|
|
|
|
"github.com/docker/docker/pkg/archive"
|
|
"github.com/docker/docker/pkg/idtools"
|
|
)
|
|
|
|
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")
|
|
}
|
|
|
|
// NewArchiver returns a new Archiver which uses chrootarchive.Untar
|
|
func NewArchiver(idMapping *idtools.IdentityMapping) *archive.Archiver {
|
|
if idMapping == nil {
|
|
idMapping = &idtools.IdentityMapping{}
|
|
}
|
|
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 {
|
|
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
|
rootIDs := idMapping.RootPair()
|
|
|
|
dest = filepath.Clean(dest)
|
|
if _, err := os.Stat(dest); os.IsNotExist(err) {
|
|
if err := idtools.MkdirAllAndChownNew(dest, 0755, rootIDs); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
r := ioutil.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)
|
|
}
|