Update vendor of storage,common

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh
2022-04-14 10:02:35 -04:00
parent 53b984f20f
commit d68e9faee2
15 changed files with 473 additions and 56 deletions

2
go.mod
View File

@ -17,7 +17,7 @@ require (
github.com/containers/image/v5 v5.21.1-0.20220405081457-d1b64686e1d0
github.com/containers/ocicrypt v1.1.3
github.com/containers/psgo v1.7.2
github.com/containers/storage v1.39.1-0.20220412073713-ea4008e14877
github.com/containers/storage v1.39.1-0.20220414183333-eea4e0f5f1f9
github.com/coreos/go-systemd/v22 v22.3.2
github.com/coreos/stream-metadata-go v0.0.0-20210225230131-70edb9eb47b3
github.com/cyphar/filepath-securejoin v0.2.3

10
go.sum
View File

@ -325,8 +325,9 @@ github.com/containerd/stargz-snapshotter/estargz v0.9.0/go.mod h1:aE5PCyhFMwR8sb
github.com/containerd/stargz-snapshotter/estargz v0.10.1/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0=
github.com/containerd/stargz-snapshotter/estargz v0.11.0/go.mod h1:/KsZXsJRllMbTKFfG0miFQWViQKdI9+9aSXs+HN0+ac=
github.com/containerd/stargz-snapshotter/estargz v0.11.1/go.mod h1:6VoPcf4M1wvnogWxqc4TqBWWErCS+R+ucnPZId2VbpQ=
github.com/containerd/stargz-snapshotter/estargz v0.11.3 h1:k2kN16Px6LYuv++qFqK+JTcYqc8bEVxzGpf8/gFBL5M=
github.com/containerd/stargz-snapshotter/estargz v0.11.3/go.mod h1:7vRJIcImfY8bpifnMjt+HTJoQxASq7T28MYbP15/Nf0=
github.com/containerd/stargz-snapshotter/estargz v0.11.4 h1:LjrYUZpyOhiSaU7hHrdR82/RBoxfGWSaC0VeSSMXqnk=
github.com/containerd/stargz-snapshotter/estargz v0.11.4/go.mod h1:7vRJIcImfY8bpifnMjt+HTJoQxASq7T28MYbP15/Nf0=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
@ -379,8 +380,8 @@ github.com/containers/storage v1.38.2/go.mod h1:INP0RPLHWBxx+pTsO5uiHlDUGHDFvWZP
github.com/containers/storage v1.38.3-0.20220301151551-d06b0f81c0aa/go.mod h1:LkkL34WRi4dI4jt9Cp+ImdZi/P5i36glSHimT5CP5zM=
github.com/containers/storage v1.39.0/go.mod h1:UAD0cKLouN4BOQRgZut/nMjrh/EnTCjSNPgp4ZuGWMs=
github.com/containers/storage v1.39.1-0.20220330193934-f3200eb5a5d9/go.mod h1:IMa2AfBI+Fxxk2hQqLTGhpJX6z2pZS1/I785QJeUwUY=
github.com/containers/storage v1.39.1-0.20220412073713-ea4008e14877 h1:V3aVdbQt9qU6tu4HHAJtro4H8+Hnv6X/hrUNba8dll0=
github.com/containers/storage v1.39.1-0.20220412073713-ea4008e14877/go.mod h1:UuYvGSKIdmzkjHbT/PENtxLRVGQ974nyhMbYp0KP19w=
github.com/containers/storage v1.39.1-0.20220414183333-eea4e0f5f1f9 h1:cB2AvqxpfyqyyffXtDN0txJhD0lIaZWktbSRI92WpN4=
github.com/containers/storage v1.39.1-0.20220414183333-eea4e0f5f1f9/go.mod h1:hFiHLMgNU0r3MiUpE97hEBaEKCN8fEIuEEBXoFC9eN0=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@ -1005,8 +1006,9 @@ github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7s
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
github.com/moby/sys/mountinfo v0.6.0 h1:gUDhXQx58YNrpHlK4nSL+7y2pxFZkUcXqzFDKWdC0Oo=
github.com/moby/sys/mountinfo v0.6.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
github.com/moby/sys/mountinfo v0.6.1 h1:+H/KnGEAGRpTrEAqNVQ2AM3SiwMgJUt/TXj+Z8cmCIc=
github.com/moby/sys/mountinfo v0.6.1/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg=
github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs=

View File

@ -26,10 +26,10 @@ import (
"archive/tar"
"bytes"
"compress/gzip"
"context"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"runtime"
@ -48,6 +48,7 @@ type options struct {
prioritizedFiles []string
missedPrioritizedFiles *[]string
compression Compression
ctx context.Context
}
type Option func(o *options) error
@ -104,6 +105,14 @@ func WithCompression(compression Compression) Option {
}
}
// WithContext specifies a context that can be used for clean canceleration.
func WithContext(ctx context.Context) Option {
return func(o *options) error {
o.ctx = ctx
return nil
}
}
// Blob is an eStargz blob.
type Blob struct {
io.ReadCloser
@ -139,12 +148,29 @@ func Build(tarBlob *io.SectionReader, opt ...Option) (_ *Blob, rErr error) {
opts.compression = newGzipCompressionWithLevel(opts.compressionLevel)
}
layerFiles := newTempFiles()
ctx := opts.ctx
if ctx == nil {
ctx = context.Background()
}
done := make(chan struct{})
defer close(done)
go func() {
select {
case <-done:
// nop
case <-ctx.Done():
layerFiles.CleanupAll()
}
}()
defer func() {
if rErr != nil {
if err := layerFiles.CleanupAll(); err != nil {
rErr = fmt.Errorf("failed to cleanup tmp files: %v: %w", err, rErr)
}
}
if cErr := ctx.Err(); cErr != nil {
rErr = fmt.Errorf("error from context %q: %w", cErr, rErr)
}
}()
tarBlob, err := decompressBlob(tarBlob, layerFiles)
if err != nil {
@ -506,12 +532,13 @@ func newTempFiles() *tempFiles {
}
type tempFiles struct {
files []*os.File
filesMu sync.Mutex
files []*os.File
filesMu sync.Mutex
cleanupOnce sync.Once
}
func (tf *tempFiles) TempFile(dir, pattern string) (*os.File, error) {
f, err := ioutil.TempFile(dir, pattern)
f, err := os.CreateTemp(dir, pattern)
if err != nil {
return nil, err
}
@ -521,7 +548,14 @@ func (tf *tempFiles) TempFile(dir, pattern string) (*os.File, error) {
return f, nil
}
func (tf *tempFiles) CleanupAll() error {
func (tf *tempFiles) CleanupAll() (err error) {
tf.cleanupOnce.Do(func() {
err = tf.cleanupAll()
})
return
}
func (tf *tempFiles) cleanupAll() error {
tf.filesMu.Lock()
defer tf.filesMu.Unlock()
var allErr []error

View File

@ -31,7 +31,6 @@ import (
"fmt"
"hash"
"io"
"io/ioutil"
"os"
"path"
"sort"
@ -579,7 +578,7 @@ func (fr *fileReader) ReadAt(p []byte, off int64) (n int, err error) {
return 0, fmt.Errorf("fileReader.ReadAt.decompressor.Reader: %v", err)
}
defer dr.Close()
if n, err := io.CopyN(ioutil.Discard, dr, off); n != off || err != nil {
if n, err := io.CopyN(io.Discard, dr, off); n != off || err != nil {
return 0, fmt.Errorf("discard of %d bytes = %v, %v", off, n, err)
}
return io.ReadFull(dr, p)
@ -933,7 +932,7 @@ func (w *Writer) appendTar(r io.Reader, lossless bool) error {
}
}
}
remainDest := ioutil.Discard
remainDest := io.Discard
if lossless {
remainDest = dst // Preserve the remaining bytes in lossless mode
}

View File

@ -31,7 +31,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"reflect"
"sort"
@ -287,11 +286,11 @@ func isSameTarGz(t *testing.T, controller TestingController, a, b []byte) bool {
return false
}
aFile, err := ioutil.ReadAll(aTar)
aFile, err := io.ReadAll(aTar)
if err != nil {
t.Fatal("failed to read tar payload of A")
}
bFile, err := ioutil.ReadAll(bTar)
bFile, err := io.ReadAll(bTar)
if err != nil {
t.Fatal("failed to read tar payload of B")
}

View File

@ -1,3 +1,4 @@
//go:build linux
// +build linux
package overlay
@ -11,6 +12,7 @@ import (
"syscall"
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/ioutils"
"github.com/containers/storage/pkg/mount"
"github.com/containers/storage/pkg/system"
@ -218,3 +220,55 @@ func doesVolatile(d string) (bool, error) {
}()
return true, nil
}
// supportsIdmappedLowerLayers checks if the kernel supports mounting overlay on top of
// a idmapped lower layer.
func supportsIdmappedLowerLayers(home string) (bool, error) {
layerDir, err := ioutil.TempDir(home, "compat")
if err != nil {
return false, err
}
defer func() {
_ = os.RemoveAll(layerDir)
}()
mergedDir := filepath.Join(layerDir, "merged")
lowerDir := filepath.Join(layerDir, "lower")
lowerMappedDir := filepath.Join(layerDir, "lower-mapped")
upperDir := filepath.Join(layerDir, "upper")
workDir := filepath.Join(layerDir, "work")
_ = idtools.MkdirAs(mergedDir, 0700, 0, 0)
_ = idtools.MkdirAs(lowerDir, 0700, 0, 0)
_ = idtools.MkdirAs(lowerMappedDir, 0700, 0, 0)
_ = idtools.MkdirAs(upperDir, 0700, 0, 0)
_ = idtools.MkdirAs(workDir, 0700, 0, 0)
idmap := []idtools.IDMap{
{
ContainerID: 0,
HostID: 0,
Size: 1,
},
}
pid, cleanupFunc, err := createUsernsProcess(idmap, idmap)
if err != nil {
return false, err
}
defer cleanupFunc()
if err := createIDMappedMount(lowerDir, lowerMappedDir, int(pid)); err != nil {
return false, errors.Wrapf(err, "create mapped mount")
}
defer unix.Unmount(lowerMappedDir, unix.MNT_DETACH)
opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerMappedDir, upperDir, workDir)
flags := uintptr(0)
if err := unix.Mount("overlay", mergedDir, "overlay", flags, opts); err != nil {
return false, err
}
defer func() {
_ = unix.Unmount(mergedDir, unix.MNT_DETACH)
}()
return true, nil
}

View File

@ -0,0 +1,160 @@
//go:build linux
// +build linux
package overlay
import (
"fmt"
"io/ioutil"
"os"
"syscall"
"unsafe"
"github.com/containers/storage/pkg/idtools"
"github.com/pkg/errors"
"golang.org/x/sys/unix"
)
type attr struct {
attrSet uint64
attrClr uint64
propagation uint64
userNs uint64
}
const (
// _MOUNT_ATTR_IDMAP - Idmap mount to @userns_fd in struct mount_attr
_MOUNT_ATTR_IDMAP = 0x00100000 //nolint:golint
// _OPEN_TREE_CLONE - Clone the source path mount
_OPEN_TREE_CLONE = 0x00000001 //nolint:golint
// _MOVE_MOUNT_F_EMPTY_PATH - Move the path referenced by the fd
_MOVE_MOUNT_F_EMPTY_PATH = 0x00000004 //nolint:golint
)
// openTree is a wrapper for the open_tree syscall
func openTree(path string, flags int) (fd int, err error) {
var _p0 *byte
if _p0, err = syscall.BytePtrFromString(path); err != nil {
return 0, err
}
r, _, e1 := syscall.Syscall6(uintptr(unix.SYS_OPEN_TREE), uintptr(0), uintptr(unsafe.Pointer(_p0)),
uintptr(flags), 0, 0, 0)
if e1 != 0 {
err = e1
}
return int(r), nil
}
// moveMount is a wrapper for the the move_mount syscall.
func moveMount(fdTree int, target string) (err error) {
var _p0, _p1 *byte
empty := ""
if _p0, err = syscall.BytePtrFromString(target); err != nil {
return err
}
if _p1, err = syscall.BytePtrFromString(empty); err != nil {
return err
}
flags := _MOVE_MOUNT_F_EMPTY_PATH
_, _, e1 := syscall.Syscall6(uintptr(unix.SYS_MOVE_MOUNT),
uintptr(fdTree), uintptr(unsafe.Pointer(_p1)),
0, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
return
}
// mountSetAttr is a wrapper for the mount_setattr syscall
func mountSetAttr(dfd int, path string, flags uint, attr *attr, size uint) (err error) {
var _p0 *byte
if _p0, err = syscall.BytePtrFromString(path); err != nil {
return err
}
_, _, e1 := syscall.Syscall6(uintptr(unix.SYS_MOUNT_SETATTR), uintptr(dfd), uintptr(unsafe.Pointer(_p0)),
uintptr(flags), uintptr(unsafe.Pointer(attr)), uintptr(size), 0)
if e1 != 0 {
err = e1
}
return
}
// createIDMappedMount creates a IDMapped bind mount from SOURCE to TARGET using the user namespace
// for the PID process.
func createIDMappedMount(source, target string, pid int) error {
path := fmt.Sprintf("/proc/%d/ns/user", pid)
userNsFile, err := os.Open(path)
if err != nil {
return errors.Wrapf(err, "unable to get user ns file descriptor for %q", path)
}
var attr attr
attr.attrSet = _MOUNT_ATTR_IDMAP
attr.attrClr = 0
attr.propagation = 0
attr.userNs = uint64(userNsFile.Fd())
defer userNsFile.Close()
targetDirFd, err := openTree(source, _OPEN_TREE_CLONE|unix.AT_RECURSIVE)
if err != nil {
return err
}
defer unix.Close(targetDirFd)
if err := mountSetAttr(targetDirFd, "", unix.AT_EMPTY_PATH|unix.AT_RECURSIVE,
&attr, uint(unsafe.Sizeof(attr))); err != nil {
return err
}
if err := os.Mkdir(target, 0700); err != nil && !os.IsExist(err) {
return err
}
return moveMount(targetDirFd, target)
}
// createUsernsProcess forks the current process and creates a user namespace using the specified
// mappings. It returns the pid of the new process.
func createUsernsProcess(uidMaps []idtools.IDMap, gidMaps []idtools.IDMap) (int, func(), error) {
pid, _, err := syscall.Syscall6(uintptr(unix.SYS_CLONE), unix.CLONE_NEWUSER|uintptr(unix.SIGCHLD), 0, 0, 0, 0, 0)
if err != 0 {
return -1, nil, err
}
if pid == 0 {
_ = unix.Prctl(unix.PR_SET_PDEATHSIG, uintptr(unix.SIGKILL), 0, 0, 0)
// just wait for the SIGKILL
for {
syscall.Syscall6(uintptr(unix.SYS_PAUSE), 0, 0, 0, 0, 0, 0)
}
}
cleanupFunc := func() {
unix.Kill(int(pid), unix.SIGKILL)
_, _ = unix.Wait4(int(pid), nil, 0, nil)
}
writeMappings := func(fname string, idmap []idtools.IDMap) error {
mappings := ""
for _, m := range idmap {
mappings = mappings + fmt.Sprintf("%d %d %d\n", m.ContainerID, m.HostID, m.Size)
}
return ioutil.WriteFile(fmt.Sprintf("/proc/%d/%s", pid, fname), []byte(mappings), 0600)
}
if err := writeMappings("uid_map", uidMaps); err != nil {
cleanupFunc()
return -1, nil, err
}
if err := writeMappings("gid_map", gidMaps); err != nil {
cleanupFunc()
return -1, nil, err
}
return int(pid), cleanupFunc, nil
}

View File

@ -39,7 +39,6 @@ import (
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/vbatts/tar-split/tar/storage"
"golang.org/x/sys/unix"
)
@ -121,6 +120,8 @@ type Driver struct {
supportsVolatile *bool
usingMetacopy bool
locker *locker.Locker
supportsIDMappedMounts *bool
}
type additionalLayerStore struct {
@ -205,6 +206,26 @@ func checkSupportVolatile(home, runhome string) (bool, error) {
return usingVolatile, nil
}
// checkAndRecordIDMappedSupport checks and stores if the kernel supports mounting overlay on top of a
// idmapped lower layer.
func checkAndRecordIDMappedSupport(home, runhome string) (bool, error) {
feature := "idmapped-lower-dir"
overlayCacheResult, overlayCacheText, err := cachedFeatureCheck(runhome, feature)
if err == nil {
if overlayCacheResult {
logrus.Debugf("Cached value indicated that overlay is supported")
return true, nil
}
logrus.Debugf("Cached value indicated that overlay is not supported")
return false, errors.New(overlayCacheText)
}
supportsIDMappedMounts, err := supportsIdmappedLowerLayers(home)
if err2 := cachedFeatureRecord(runhome, feature, supportsIDMappedMounts, ""); err2 != nil {
return false, errors.Wrap(err2, "recording overlay idmapped mounts support status")
}
return supportsIDMappedMounts, err
}
func checkAndRecordOverlaySupport(fsMagic graphdriver.FsMagic, home, runhome string) (bool, error) {
var supportsDType bool
@ -1485,6 +1506,51 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
}
}
if d.supportsIDmappedMounts() && len(options.UidMaps) > 0 && len(options.GidMaps) > 0 {
var newAbsDir []string
mappedRoot := filepath.Join(d.home, id, "mapped")
if err := os.MkdirAll(mappedRoot, 0700); err != nil {
return "", err
}
pid, cleanupFunc, err := createUsernsProcess(options.UidMaps, options.GidMaps)
if err != nil {
return "", err
}
defer cleanupFunc()
idMappedMounts := make(map[string]string)
// rewrite the lower dirs to their idmapped mount.
c := 0
for _, absLower := range absLowers {
mappedMountSrc := getMappedMountRoot(absLower)
root, found := idMappedMounts[mappedMountSrc]
if !found {
root = filepath.Join(mappedRoot, fmt.Sprintf("%d", c))
c++
if err := createIDMappedMount(mappedMountSrc, root, int(pid)); err != nil {
return "", errors.Wrapf(err, "create mapped mount for %q on %q", mappedMountSrc, root)
}
idMappedMounts[mappedMountSrc] = root
// overlay takes a reference on the mount, so it is safe to unmount
// the mapped idmounts as soon as the final overlay file system is mounted.
defer unix.Unmount(root, unix.MNT_DETACH)
}
// relative path to the layer through the id mapped mount
rel, err := filepath.Rel(mappedMountSrc, absLower)
if err != nil {
return "", err
}
newAbsDir = append(newAbsDir, filepath.Join(root, rel))
}
absLowers = newAbsDir
}
var opts string
if readWrite {
opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(absLowers, ":"), diffDir, workdir)
@ -1587,6 +1653,18 @@ func (d *Driver) Put(id string) error {
unmounted := false
mappedRoot := filepath.Join(d.home, id, "mapped")
// It should not happen, but cleanup any mapped mount if it was leaked.
if _, err := os.Stat(mappedRoot); err == nil {
mounts, err := ioutil.ReadDir(mappedRoot)
if err == nil {
// Go through all of the mapped mounts.
for _, m := range mounts {
_ = unix.Unmount(filepath.Join(mappedRoot, m.Name()), unix.MNT_DETACH)
}
}
}
if d.options.mountProgram != "" {
// Attempt to unmount the FUSE mount using either fusermount or fusermount3.
// If they fail, fallback to unix.Unmount
@ -1664,11 +1742,24 @@ func (d *Driver) getWhiteoutFormat() archive.WhiteoutFormat {
return whiteoutFormat
}
type fileGetNilCloser struct {
storage.FileGetter
type overlayFileGetter struct {
diffDirs []string
}
func (f fileGetNilCloser) Close() error {
func (g *overlayFileGetter) Get(path string) (io.ReadCloser, error) {
for _, d := range g.diffDirs {
f, err := os.Open(filepath.Join(d, path))
if err == nil {
return f, nil
}
}
if len(g.diffDirs) > 0 {
return os.Open(filepath.Join(g.diffDirs[0], path))
}
return nil, fmt.Errorf("%s: %w", path, os.ErrNotExist)
}
func (g *overlayFileGetter) Close() error {
return nil
}
@ -1677,13 +1768,18 @@ func (d *Driver) getStagingDir() string {
}
// DiffGetter returns a FileGetCloser that can read files from the directory that
// contains files for the layer differences. Used for direct access for tar-split.
// contains files for the layer differences, either for this layer, or one of our
// lowers if we're just a template directory. Used for direct access for tar-split.
func (d *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) {
p, err := d.getDiffPath(id)
if err != nil {
return nil, err
}
return fileGetNilCloser{storage.NewPathFileGetter(p)}, nil
paths, err := d.getLowerDiffPaths(id)
if err != nil {
return nil, err
}
return &overlayFileGetter{diffDirs: append([]string{p}, paths...)}, nil
}
// CleanupStagingDirectory cleanups the staging directory.
@ -1958,12 +2054,31 @@ func (d *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMapp
return nil
}
// supportsIDmappedMounts returns whether the kernel supports using idmapped mounts with
// overlay lower layers.
func (d *Driver) supportsIDmappedMounts() bool {
if d.supportsIDMappedMounts != nil {
return *d.supportsIDMappedMounts
}
supportsIDMappedMounts, err := checkAndRecordIDMappedSupport(d.home, d.runhome)
d.supportsIDMappedMounts = &supportsIDMappedMounts
if err == nil {
return supportsIDMappedMounts
}
logrus.Debugf("Check for idmapped mounts support %v", err)
return false
}
// SupportsShifting tells whether the driver support shifting of the UIDs/GIDs in an userNS
func (d *Driver) SupportsShifting() bool {
if os.Getenv("_TEST_FORCE_SUPPORT_SHIFTING") == "yes-please" {
return true
}
return d.options.mountProgram != ""
if d.options.mountProgram != "" {
return true
}
return d.supportsIDmappedMounts()
}
// dumbJoin is more or less a dumber version of filepath.Join, but one which
@ -2132,3 +2247,15 @@ func redirectDiffIfAdditionalLayer(diffPath string) (string, error) {
}
return diffPath, nil
}
// getMappedMountRoot is a heuristic that calculates the parent directory where
// the idmapped mount should be applied.
// It is useful to minimize the number of idmapped mounts and at the same time use
// a common path as long as possible to reduce the length of the mount data argument.
func getMappedMountRoot(path string) string {
dirName := filepath.Dir(path)
if filepath.Base(dirName) == linkDir {
return filepath.Dir(dirName)
}
return dirName
}

View File

@ -6,7 +6,7 @@ require (
github.com/BurntSushi/toml v1.1.0
github.com/Microsoft/go-winio v0.5.2
github.com/Microsoft/hcsshim v0.9.2
github.com/containerd/stargz-snapshotter/estargz v0.11.3
github.com/containerd/stargz-snapshotter/estargz v0.11.4
github.com/cyphar/filepath-securejoin v0.2.3
github.com/docker/go-units v0.4.0
github.com/google/go-intervals v0.0.2
@ -16,7 +16,7 @@ require (
github.com/klauspost/pgzip v1.2.5
github.com/mattn/go-shellwords v1.0.12
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible
github.com/moby/sys/mountinfo v0.6.0
github.com/moby/sys/mountinfo v0.6.1
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/runc v1.1.1
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417

View File

@ -176,8 +176,8 @@ github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFY
github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM=
github.com/containerd/stargz-snapshotter/estargz v0.11.3 h1:k2kN16Px6LYuv++qFqK+JTcYqc8bEVxzGpf8/gFBL5M=
github.com/containerd/stargz-snapshotter/estargz v0.11.3/go.mod h1:7vRJIcImfY8bpifnMjt+HTJoQxASq7T28MYbP15/Nf0=
github.com/containerd/stargz-snapshotter/estargz v0.11.4 h1:LjrYUZpyOhiSaU7hHrdR82/RBoxfGWSaC0VeSSMXqnk=
github.com/containerd/stargz-snapshotter/estargz v0.11.4/go.mod h1:7vRJIcImfY8bpifnMjt+HTJoQxASq7T28MYbP15/Nf0=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
@ -467,8 +467,8 @@ github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQ
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
github.com/moby/sys/mountinfo v0.6.0 h1:gUDhXQx58YNrpHlK4nSL+7y2pxFZkUcXqzFDKWdC0Oo=
github.com/moby/sys/mountinfo v0.6.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
github.com/moby/sys/mountinfo v0.6.1 h1:+H/KnGEAGRpTrEAqNVQ2AM3SiwMgJUt/TXj+Z8cmCIc=
github.com/moby/sys/mountinfo v0.6.1/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=

View File

@ -725,12 +725,32 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab
parent = parentLayer.ID
}
var parentMappings, templateIDMappings, oldMappings *idtools.IDMappings
var (
templateMetadata string
templateCompressedDigest digest.Digest
templateCompressedSize int64
templateUncompressedDigest digest.Digest
templateUncompressedSize int64
templateCompressionType archive.Compression
templateUIDs, templateGIDs []uint32
templateTSdata []byte
)
if moreOptions.TemplateLayer != "" {
var tserr error
templateLayer, ok := r.lookup(moreOptions.TemplateLayer)
if !ok {
return nil, -1, ErrLayerUnknown
}
templateMetadata = templateLayer.Metadata
templateIDMappings = idtools.NewIDMappingsFromMaps(templateLayer.UIDMap, templateLayer.GIDMap)
templateCompressedDigest, templateCompressedSize = templateLayer.CompressedDigest, templateLayer.CompressedSize
templateUncompressedDigest, templateUncompressedSize = templateLayer.UncompressedDigest, templateLayer.UncompressedSize
templateCompressionType = templateLayer.CompressionType
templateUIDs, templateGIDs = append([]uint32{}, templateLayer.UIDs...), append([]uint32{}, templateLayer.GIDs...)
templateTSdata, tserr = ioutil.ReadFile(r.tspath(templateLayer.ID))
if tserr != nil && !os.IsNotExist(tserr) {
return nil, -1, tserr
}
} else {
templateIDMappings = &idtools.IDMappings{}
}
@ -775,17 +795,43 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab
return nil, -1, err
}
}
if len(templateTSdata) > 0 {
if err := os.MkdirAll(filepath.Dir(r.tspath(id)), 0o700); err != nil {
// We don't have a record of this layer, but at least
// try to clean it up underneath us.
if err2 := r.driver.Remove(id); err2 != nil {
logrus.Errorf("While recovering from a failure creating in UpdateLayerIDMap, error deleting layer %#v: %v", id, err2)
}
return nil, -1, err
}
if err = ioutils.AtomicWriteFile(r.tspath(id), templateTSdata, 0o600); err != nil {
// We don't have a record of this layer, but at least
// try to clean it up underneath us.
if err2 := r.driver.Remove(id); err2 != nil {
logrus.Errorf("While recovering from a failure creating in UpdateLayerIDMap, error deleting layer %#v: %v", id, err2)
}
return nil, -1, err
}
}
if err == nil {
layer = &Layer{
ID: id,
Parent: parent,
Names: names,
MountLabel: mountLabel,
Created: time.Now().UTC(),
Flags: make(map[string]interface{}),
UIDMap: copyIDMap(moreOptions.UIDMap),
GIDMap: copyIDMap(moreOptions.GIDMap),
BigDataNames: []string{},
ID: id,
Parent: parent,
Names: names,
MountLabel: mountLabel,
Metadata: templateMetadata,
Created: time.Now().UTC(),
CompressedDigest: templateCompressedDigest,
CompressedSize: templateCompressedSize,
UncompressedDigest: templateUncompressedDigest,
UncompressedSize: templateUncompressedSize,
CompressionType: templateCompressionType,
UIDs: templateUIDs,
GIDs: templateGIDs,
Flags: make(map[string]interface{}),
UIDMap: copyIDMap(moreOptions.UIDMap),
GIDMap: copyIDMap(moreOptions.GIDMap),
BigDataNames: []string{},
}
r.layers = append(r.layers, layer)
r.idindex.Add(id)
@ -872,7 +918,6 @@ func (r *layerStore) Mounted(id string) (int, error) {
}
func (r *layerStore) Mount(id string, options drivers.MountOpts) (string, error) {
// check whether options include ro option
hasReadOnlyOpt := func(opts []string) bool {
for _, item := range opts {

View File

@ -2452,6 +2452,10 @@ func (s *store) DeleteImage(id string, commit bool) (layers []string, err error)
}
layer := image.TopLayer
layersToRemoveMap := make(map[string]struct{})
layersToRemove = append(layersToRemove, image.MappedTopLayers...)
for _, mappedTopLayer := range image.MappedTopLayers {
layersToRemoveMap[mappedTopLayer] = struct{}{}
}
for layer != "" {
if rcstore.Exists(layer) {
break
@ -2483,12 +2487,6 @@ func (s *store) DeleteImage(id string, commit bool) (layers []string, err error)
if hasChildrenNotBeingRemoved() {
break
}
if layer == image.TopLayer {
layersToRemove = append(layersToRemove, image.MappedTopLayers...)
for _, mappedTopLayer := range image.MappedTopLayers {
layersToRemoveMap[mappedTopLayer] = struct{}{}
}
}
layersToRemove = append(layersToRemove, layer)
layersToRemoveMap[layer] = struct{}{}
layer = parent

View File

@ -42,13 +42,14 @@ func validateMountOptions(mountOptions []string) error {
}
func applyNameOperation(oldNames []string, opParameters []string, op updateNameOperation) ([]string, error) {
result := make([]string, 0)
var result []string
switch op {
case setNames:
// ignore all old names and just return new names
return dedupeNames(opParameters), nil
result = opParameters
case removeNames:
// remove given names from old names
result = make([]string, 0, len(oldNames))
for _, name := range oldNames {
// only keep names in final result which do not intersect with input names
// basically `result = oldNames - opParameters`
@ -62,11 +63,10 @@ func applyNameOperation(oldNames []string, opParameters []string, op updateNameO
result = append(result, name)
}
}
return dedupeNames(result), nil
case addNames:
result = make([]string, 0, len(opParameters)+len(oldNames))
result = append(result, opParameters...)
result = append(result, oldNames...)
return dedupeNames(result), nil
default:
return result, errInvalidUpdateNameOperation
}

View File

@ -4,7 +4,6 @@
package mountinfo
import (
"fmt"
"os"
"path/filepath"
@ -33,13 +32,13 @@ func mountedByStat(path string) (bool, error) {
func normalizePath(path string) (realPath string, err error) {
if realPath, err = filepath.Abs(path); err != nil {
return "", fmt.Errorf("unable to get absolute path for %q: %w", path, err)
return "", err
}
if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
return "", fmt.Errorf("failed to canonicalise path for %q: %w", path, err)
return "", err
}
if _, err := os.Stat(realPath); err != nil {
return "", fmt.Errorf("failed to stat target of %q: %w", path, err)
return "", err
}
return realPath, nil
}

6
vendor/modules.txt vendored
View File

@ -69,7 +69,7 @@ github.com/containerd/containerd/log
github.com/containerd/containerd/pkg/userns
github.com/containerd/containerd/platforms
github.com/containerd/containerd/sys
# github.com/containerd/stargz-snapshotter/estargz v0.11.3
# github.com/containerd/stargz-snapshotter/estargz v0.11.4
github.com/containerd/stargz-snapshotter/estargz
github.com/containerd/stargz-snapshotter/estargz/errorutil
# github.com/containernetworking/cni v1.0.1
@ -233,7 +233,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/host
github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process
# github.com/containers/storage v1.39.1-0.20220412073713-ea4008e14877
# github.com/containers/storage v1.39.1-0.20220414183333-eea4e0f5f1f9
## explicit
github.com/containers/storage
github.com/containers/storage/drivers
@ -479,7 +479,7 @@ github.com/mistifyio/go-zfs
github.com/mitchellh/mapstructure
# github.com/moby/sys/mount v0.2.0
github.com/moby/sys/mount
# github.com/moby/sys/mountinfo v0.6.0
# github.com/moby/sys/mountinfo v0.6.1
github.com/moby/sys/mountinfo
# github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
## explicit