mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
[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:
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -52,6 +52,7 @@ go_library(
|
||||
"//pkg/fspath",
|
||||
"//pkg/log",
|
||||
"//pkg/p9",
|
||||
"//pkg/refs",
|
||||
"//pkg/safemem",
|
||||
"//pkg/sentry/fs/fsutil",
|
||||
"//pkg/sentry/fs/lock",
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user