integration: detect double released and leaked mountpoints

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
docker-19.03
Tonis Tiigi 2019-08-15 16:14:02 -07:00
parent a0dead0809
commit b8284301fd
2 changed files with 40 additions and 5 deletions

View File

@ -2,7 +2,9 @@ package snapshot
import (
"context"
"os"
"sync"
"sync/atomic"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/snapshots"
@ -62,7 +64,7 @@ func (s *fromContainerd) Mounts(ctx context.Context, key string) (Mountable, err
if err != nil {
return nil, err
}
return &staticMountable{mounts, s.idmap}, nil
return &staticMountable{mounts: mounts, idmap: s.idmap, id: key}, nil
}
func (s *fromContainerd) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) error {
_, err := s.Snapshotter.Prepare(ctx, key, parent, opts...)
@ -73,19 +75,29 @@ func (s *fromContainerd) View(ctx context.Context, key, parent string, opts ...s
if err != nil {
return nil, err
}
return &staticMountable{mounts, s.idmap}, nil
return &staticMountable{mounts: mounts, idmap: s.idmap, id: key}, nil
}
func (s *fromContainerd) IdentityMapping() *idtools.IdentityMapping {
return s.idmap
}
type staticMountable struct {
count int32
id string
mounts []mount.Mount
idmap *idtools.IdentityMapping
}
func (m *staticMountable) Mount() ([]mount.Mount, func() error, error) {
return m.mounts, func() error { return nil }, nil
func (cm *staticMountable) Mount() ([]mount.Mount, func() error, error) {
atomic.AddInt32(&cm.count, 1)
return cm.mounts, func() error {
if atomic.AddInt32(&cm.count, -1) < 0 {
if v := os.Getenv("BUILDKIT_DEBUG_PANIC_ON_ERROR"); v == "1" {
panic("release of released mount " + cm.id)
}
}
return nil
}, nil
}
func (cm *staticMountable) IdentityMapping() *idtools.IdentityMapping {

View File

@ -10,6 +10,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
"strings"
"syscall"
"testing"
"time"
@ -181,6 +182,13 @@ func runBuildkitd(args []string, logs map[string]*bytes.Buffer, uid, gid int) (a
if err := os.Chown(tmpdir, uid, gid); err != nil {
return "", nil, err
}
if err := os.MkdirAll(filepath.Join(tmpdir, "tmp"), 0711); err != nil {
return "", nil, err
}
if err := os.Chown(filepath.Join(tmpdir, "tmp"), uid, gid); err != nil {
return "", nil, err
}
deferF.append(func() error { return os.RemoveAll(tmpdir) })
address = "unix://" + filepath.Join(tmpdir, "buildkitd.sock")
@ -190,7 +198,7 @@ func runBuildkitd(args []string, logs map[string]*bytes.Buffer, uid, gid int) (a
args = append(args, "--root", tmpdir, "--addr", address, "--debug")
cmd := exec.Command(args[0], args[1:]...)
cmd.Env = append(os.Environ(), "BUILDKIT_DEBUG_EXEC_OUTPUT=1")
cmd.Env = append(os.Environ(), "BUILDKIT_DEBUG_EXEC_OUTPUT=1", "BUILDKIT_DEBUG_PANIC_ON_ERROR=1", "TMPDIR="+filepath.Join(tmpdir, "tmp"))
cmd.SysProcAttr = &syscall.SysProcAttr{
Setsid: true, // stretch sudo needs this for sigterm
}
@ -205,6 +213,21 @@ func runBuildkitd(args []string, logs map[string]*bytes.Buffer, uid, gid int) (a
return "", nil, err
}
deferF.append(func() error {
f, err := os.Open("/proc/self/mountinfo")
if err != nil {
return errors.Wrap(err, "failed to open mountinfo")
}
defer f.Close()
s := bufio.NewScanner(f)
for s.Scan() {
if strings.Contains(s.Text(), tmpdir) {
return errors.Errorf("leaked mountpoint for %s", tmpdir)
}
}
return s.Err()
})
return
}