[vfs2] Don't take reference in Task.MountNamespaceVFS2 and MountNamespace.Root.

This fixes reference leaks related to accidentally forgetting to DecRef()
after calling one or the other.

PiperOrigin-RevId: 336918922
This commit is contained in:
Dean Deng
2020-10-13 11:31:22 -07:00
committed by gVisor bot
parent d9b32efb30
commit 432963dd2d
21 changed files with 54 additions and 34 deletions
+2 -2
View File
@@ -183,9 +183,9 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI
if initArgs.MountNamespaceVFS2 == nil {
// Set initArgs so that 'ctx' returns the namespace.
//
// MountNamespaceVFS2 adds a reference to the namespace, which is
// transferred to the new process.
// Add a reference to the namespace, which is transferred to the new process.
initArgs.MountNamespaceVFS2 = proc.Kernel.GlobalInit().Leader().MountNamespaceVFS2()
initArgs.MountNamespaceVFS2.IncRef()
}
} else {
if initArgs.MountNamespace == nil {
+1
View File
@@ -121,6 +121,7 @@ func resolve(ctx context.Context, mns *fs.MountNamespace, paths []string, name s
func resolveVFS2(ctx context.Context, creds *auth.Credentials, mns *vfs.MountNamespace, paths []string, name string) (string, error) {
root := mns.Root()
root.IncRef()
defer root.DecRef(ctx)
for _, p := range paths {
if !path.IsAbs(p) {
+1
View File
@@ -105,6 +105,7 @@ func getExecUserHomeVFS2(ctx context.Context, mns *vfs.MountNamespace, uid auth.
const defaultHome = "/"
root := mns.Root()
root.IncRef()
defer root.DecRef(ctx)
creds := auth.CredentialsFromContext(ctx)
+4 -1
View File
@@ -95,10 +95,13 @@ func NewAccessor(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth
if err != nil {
return nil, err
}
// Pass a reference on root to the Accessor.
root := mntns.Root()
root.IncRef()
return &Accessor{
vfsObj: vfsObj,
mntns: mntns,
root: mntns.Root(),
root: root,
creds: creds,
}, nil
}
@@ -53,6 +53,7 @@ func setupDevtmpfs(t *testing.T) (context.Context, *auth.Credentials, *vfs.Virtu
t.Fatalf("failed to create tmpfs root mount: %v", err)
}
root := mntns.Root()
root.IncRef()
devpop := vfs.PathOperation{
Root: root,
Start: root,
@@ -70,6 +70,7 @@ func setUp(b *testing.B, imagePath string) (context.Context, *vfs.VirtualFilesys
}
root := mntns.Root()
root.IncRef()
tearDown := func() {
root.DecRef(ctx)
+1
View File
@@ -82,6 +82,7 @@ func setUp(t *testing.T, imagePath string) (context.Context, *vfs.VirtualFilesys
}
root := mntns.Root()
root.IncRef()
tearDown := func() {
root.DecRef(ctx)
+1
View File
@@ -52,6 +52,7 @@ go_library(
"//pkg/fspath",
"//pkg/log",
"//pkg/p9",
"//pkg/refs",
"//pkg/safemem",
"//pkg/sentry/fs/fsutil",
"//pkg/sentry/fs/lock",
+7 -4
View File
@@ -109,9 +109,12 @@ func setup(t *testing.T) *testutil.System {
if err != nil {
t.Fatalf("NewMountNamespace(): %v", err)
}
root := mntns.Root()
root.IncRef()
defer root.DecRef(ctx)
pop := &vfs.PathOperation{
Root: mntns.Root(),
Start: mntns.Root(),
Root: root,
Start: root,
Path: fspath.Parse("/proc"),
}
if err := k.VFS().MkdirAt(ctx, creds, pop, &vfs.MkdirOptions{Mode: 0777}); err != nil {
@@ -119,8 +122,8 @@ func setup(t *testing.T) *testutil.System {
}
pop = &vfs.PathOperation{
Root: mntns.Root(),
Start: mntns.Root(),
Root: root,
Start: root,
Path: fspath.Parse("/proc"),
}
mntOpts := &vfs.MountOptions{
+6 -4
View File
@@ -46,16 +46,18 @@ type System struct {
// NewSystem constructs a System.
//
// Precondition: Caller must hold a reference on MntNs, whose ownership
// Precondition: Caller must hold a reference on mns, whose ownership
// is transferred to the new System.
func NewSystem(ctx context.Context, t *testing.T, v *vfs.VirtualFilesystem, mns *vfs.MountNamespace) *System {
root := mns.Root()
root.IncRef()
s := &System{
t: t,
Ctx: ctx,
Creds: auth.CredentialsFromContext(ctx),
VFS: v,
MntNs: mns,
Root: mns.Root(),
Root: root,
}
return s
}
@@ -254,10 +256,10 @@ func (d *DirentCollector) Contains(name string, typ uint8) error {
defer d.mu.Unlock()
dirent, ok := d.dirents[name]
if !ok {
return fmt.Errorf("No dirent named %q found", name)
return fmt.Errorf("no dirent named %q found", name)
}
if dirent.Type != typ {
return fmt.Errorf("Dirent named %q found, but was expecting type %s, got: %+v", name, linux.DirentType.Parse(uint64(typ)), dirent)
return fmt.Errorf("dirent named %q found, but was expecting type %s, got: %+v", name, linux.DirentType.Parse(uint64(typ)), dirent)
}
return nil
}
@@ -193,6 +193,7 @@ func BenchmarkVFS2TmpfsStat(b *testing.B) {
// Create nested directories with given depth.
root := mntns.Root()
root.IncRef()
defer root.DecRef(ctx)
vd := root
vd.IncRef()
@@ -387,6 +388,7 @@ func BenchmarkVFS2TmpfsMountStat(b *testing.B) {
// Create the mount point.
root := mntns.Root()
root.IncRef()
defer root.DecRef(ctx)
pop := vfs.PathOperation{
Root: root,
+1
View File
@@ -165,6 +165,7 @@ func setup(t *testing.T) (context.Context, *auth.Credentials, *vfs.VirtualFilesy
// Create the pipe.
root := mntns.Root()
root.IncRef()
pop := vfs.PathOperation{
Root: root,
Start: root,
+1
View File
@@ -46,6 +46,7 @@ func newTmpfsRoot(ctx context.Context) (*vfs.VirtualFilesystem, vfs.VirtualDentr
return nil, vfs.VirtualDentry{}, nil, fmt.Errorf("failed to create tmpfs root mount: %v", err)
}
root := mntns.Root()
root.IncRef()
return vfsObj, root, func() {
root.DecRef(ctx)
mntns.DecRef(ctx)
+1
View File
@@ -70,6 +70,7 @@ func newVerityRoot(ctx context.Context, t *testing.T) (*vfs.VirtualFilesystem, v
return nil, vfs.VirtualDentry{}, fmt.Errorf("NewMountNamespace: %v", err)
}
root := mntns.Root()
root.IncRef()
t.Helper()
t.Cleanup(func() {
root.DecRef(ctx)
+15 -14
View File
@@ -841,14 +841,16 @@ func (ctx *createProcessContext) Value(key interface{}) interface{} {
if ctx.args.MountNamespaceVFS2 == nil {
return nil
}
// MountNamespaceVFS2.Root() takes a reference on the root dirent for us.
return ctx.args.MountNamespaceVFS2.Root()
root := ctx.args.MountNamespaceVFS2.Root()
root.IncRef()
return root
case vfs.CtxMountNamespace:
if ctx.k.globalInit == nil {
return nil
}
// MountNamespaceVFS2 takes a reference for us.
return ctx.k.GlobalInit().Leader().MountNamespaceVFS2()
mntns := ctx.k.GlobalInit().Leader().MountNamespaceVFS2()
mntns.IncRef()
return mntns
case fs.CtxDirentCacheLimiter:
return ctx.k.DirentCacheLimiter
case inet.CtxStack:
@@ -904,14 +906,13 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
if VFS2Enabled {
mntnsVFS2 = args.MountNamespaceVFS2
if mntnsVFS2 == nil {
// MountNamespaceVFS2 adds a reference to the namespace, which is
// transferred to the new process.
// Add a reference to the namespace, which is transferred to the new process.
mntnsVFS2 = k.globalInit.Leader().MountNamespaceVFS2()
mntnsVFS2.IncRef()
}
// Get the root directory from the MountNamespace.
root := mntnsVFS2.Root()
// The call to newFSContext below will take a reference on root, so we
// don't need to hold this one.
root.IncRef()
defer root.DecRef(ctx)
// Grab the working directory.
@@ -1648,16 +1649,16 @@ func (ctx supervisorContext) Value(key interface{}) interface{} {
if ctx.k.globalInit == nil {
return vfs.VirtualDentry{}
}
mntns := ctx.k.GlobalInit().Leader().MountNamespaceVFS2()
defer mntns.DecRef(ctx)
// Root() takes a reference on the root dirent for us.
return mntns.Root()
root := ctx.k.GlobalInit().Leader().MountNamespaceVFS2().Root()
root.IncRef()
return root
case vfs.CtxMountNamespace:
if ctx.k.globalInit == nil {
return nil
}
// MountNamespaceVFS2() takes a reference for us.
return ctx.k.GlobalInit().Leader().MountNamespaceVFS2()
mntns := ctx.k.GlobalInit().Leader().MountNamespaceVFS2()
mntns.IncRef()
return mntns
case fs.CtxDirentCacheLimiter:
return ctx.k.DirentCacheLimiter
case inet.CtxStack:
-2
View File
@@ -735,7 +735,6 @@ func (t *Task) SyscallRestartBlock() SyscallRestartBlock {
func (t *Task) IsChrooted() bool {
if VFS2Enabled {
realRoot := t.mountNamespaceVFS2.Root()
defer realRoot.DecRef(t)
root := t.fsContext.RootDirectoryVFS2()
defer root.DecRef(t)
return root != realRoot
@@ -868,7 +867,6 @@ func (t *Task) MountNamespace() *fs.MountNamespace {
func (t *Task) MountNamespaceVFS2() *vfs.MountNamespace {
t.mu.Lock()
defer t.mu.Unlock()
t.mountNamespaceVFS2.IncRef()
return t.mountNamespaceVFS2
}
+1 -2
View File
@@ -110,8 +110,7 @@ func execveat(t *kernel.Task, dirfd int32, pathnameAddr, argvAddr, envvAddr user
}
// Load the new TaskContext.
mntns := t.MountNamespaceVFS2() // FIXME(jamieliu): useless refcount change
defer mntns.DecRef(t)
mntns := t.MountNamespaceVFS2()
wd := t.FSContext().WorkingDirectoryVFS2()
defer wd.DecRef(t)
remainingTraversals := uint(linux.MaxSymlinkTraversals)
+1 -3
View File
@@ -727,14 +727,12 @@ func (mnt *Mount) Root() *Dentry {
return mnt.root
}
// Root returns mntns' root. A reference is taken on the returned
// VirtualDentry.
// Root returns mntns' root. It does not take a reference on the returned Dentry.
func (mntns *MountNamespace) Root() VirtualDentry {
vd := VirtualDentry{
mount: mntns.root,
dentry: mntns.root.root,
}
vd.IncRef()
return vd
}
+1 -2
View File
@@ -903,7 +903,7 @@ func (l *Loader) executeAsync(args *control.ExecArgs) (kernel.ThreadID, error) {
// Get the container MountNamespace from the Task. Try to acquire ref may fail
// in case it raced with task exit.
if kernel.VFS2Enabled {
// task.MountNamespace() does not take a ref, so we must do so ourselves.
// task.MountNamespaceVFS2() does not take a ref, so we must do so ourselves.
args.MountNamespaceVFS2 = tg.Leader().MountNamespaceVFS2()
if !args.MountNamespaceVFS2.TryIncRef() {
return 0, fmt.Errorf("container %q has stopped", args.ContainerID)
@@ -925,7 +925,6 @@ func (l *Loader) executeAsync(args *control.ExecArgs) (kernel.ThreadID, error) {
root := args.MountNamespaceVFS2.Root()
ctx := vfs.WithRoot(l.k.SupervisorContext(), root)
defer args.MountNamespaceVFS2.DecRef(ctx)
defer root.DecRef(ctx)
envv, err := user.MaybeAddExecUserHomeVFS2(ctx, args.MountNamespaceVFS2, args.KUID, args.Envv)
if err != nil {
return 0, err
+1
View File
@@ -491,6 +491,7 @@ func TestCreateMountNamespaceVFS2(t *testing.T) {
}
root := mns.Root()
root.IncRef()
defer root.DecRef(ctx)
for _, p := range tc.expectedPaths {
target := &vfs.PathOperation{

Some files were not shown because too many files have changed in this diff Show More