mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
[vfs2] Fix fork reference leaks.
PiperOrigin-RevId: 337919424
This commit is contained in:
@@ -147,7 +147,12 @@ func CreateTask(ctx context.Context, name string, tc *kernel.ThreadGroup, mntns
|
||||
FSContext: kernel.NewFSContextVFS2(root, cwd, 0022),
|
||||
FDTable: k.NewFDTable(),
|
||||
}
|
||||
return k.TaskSet().NewTask(config)
|
||||
t, err := k.TaskSet().NewTask(ctx, config)
|
||||
if err != nil {
|
||||
config.ThreadGroup.Release(ctx)
|
||||
return nil, err
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func newFakeExecutable(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, root vfs.VirtualDentry) (*vfs.FileDescription, error) {
|
||||
|
||||
@@ -218,6 +218,7 @@ go_library(
|
||||
"//pkg/amutex",
|
||||
"//pkg/bits",
|
||||
"//pkg/bpf",
|
||||
"//pkg/cleanup",
|
||||
"//pkg/context",
|
||||
"//pkg/coverage",
|
||||
"//pkg/cpuid",
|
||||
|
||||
@@ -39,6 +39,7 @@ import (
|
||||
"time"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/cleanup"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/cpuid"
|
||||
"gvisor.dev/gvisor/pkg/eventchannel"
|
||||
@@ -340,7 +341,7 @@ func (k *Kernel) Init(args InitKernelArgs) error {
|
||||
return fmt.Errorf("Timekeeper is nil")
|
||||
}
|
||||
if args.Timekeeper.clocks == nil {
|
||||
return fmt.Errorf("Must call Timekeeper.SetClocks() before Kernel.Init()")
|
||||
return fmt.Errorf("must call Timekeeper.SetClocks() before Kernel.Init()")
|
||||
}
|
||||
if args.RootUserNamespace == nil {
|
||||
return fmt.Errorf("RootUserNamespace is nil")
|
||||
@@ -365,7 +366,7 @@ func (k *Kernel) Init(args InitKernelArgs) error {
|
||||
k.useHostCores = true
|
||||
maxCPU, err := hostcpu.MaxPossibleCPU()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get maximum CPU number: %v", err)
|
||||
return fmt.Errorf("failed to get maximum CPU number: %v", err)
|
||||
}
|
||||
minAppCores := uint(maxCPU) + 1
|
||||
if k.applicationCores < minAppCores {
|
||||
@@ -966,6 +967,10 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
|
||||
}
|
||||
|
||||
tg := k.NewThreadGroup(mntns, args.PIDNamespace, NewSignalHandlers(), linux.SIGCHLD, args.Limits)
|
||||
cu := cleanup.Make(func() {
|
||||
tg.Release(ctx)
|
||||
})
|
||||
defer cu.Clean()
|
||||
|
||||
// Check which file to start from.
|
||||
switch {
|
||||
@@ -1025,13 +1030,14 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
|
||||
MountNamespaceVFS2: mntnsVFS2,
|
||||
ContainerID: args.ContainerID,
|
||||
}
|
||||
t, err := k.tasks.NewTask(config)
|
||||
t, err := k.tasks.NewTask(ctx, config)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
t.traceExecEvent(tc) // Simulate exec for tracing.
|
||||
|
||||
// Success.
|
||||
cu.Release()
|
||||
tgid := k.tasks.Root.IDOfThreadGroup(tg)
|
||||
if k.globalInit == nil {
|
||||
k.globalInit = tg
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/bpf"
|
||||
"gvisor.dev/gvisor/pkg/cleanup"
|
||||
"gvisor.dev/gvisor/pkg/sentry/inet"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
@@ -206,6 +207,10 @@ func (t *Task) Clone(opts *CloneOptions) (ThreadID, *SyscallControl, error) {
|
||||
} else {
|
||||
ipcns.IncRef()
|
||||
}
|
||||
cu := cleanup.Make(func() {
|
||||
ipcns.DecRef(t)
|
||||
})
|
||||
defer cu.Clean()
|
||||
|
||||
netns := t.NetworkNamespace()
|
||||
if opts.NewNetworkNamespace {
|
||||
@@ -216,13 +221,18 @@ func (t *Task) Clone(opts *CloneOptions) (ThreadID, *SyscallControl, error) {
|
||||
mntnsVFS2 := t.mountNamespaceVFS2
|
||||
if mntnsVFS2 != nil {
|
||||
mntnsVFS2.IncRef()
|
||||
cu.Add(func() {
|
||||
mntnsVFS2.DecRef(t)
|
||||
})
|
||||
}
|
||||
|
||||
tc, err := t.tc.Fork(t, t.k, !opts.NewAddressSpace)
|
||||
if err != nil {
|
||||
ipcns.DecRef(t)
|
||||
return 0, nil, err
|
||||
}
|
||||
cu.Add(func() {
|
||||
tc.release()
|
||||
})
|
||||
// clone() returns 0 in the child.
|
||||
tc.Arch.SetReturn(0)
|
||||
if opts.Stack != 0 {
|
||||
@@ -230,7 +240,6 @@ func (t *Task) Clone(opts *CloneOptions) (ThreadID, *SyscallControl, error) {
|
||||
}
|
||||
if opts.SetTLS {
|
||||
if !tc.Arch.SetTLS(uintptr(opts.TLS)) {
|
||||
ipcns.DecRef(t)
|
||||
return 0, nil, syserror.EPERM
|
||||
}
|
||||
}
|
||||
@@ -299,11 +308,11 @@ func (t *Task) Clone(opts *CloneOptions) (ThreadID, *SyscallControl, error) {
|
||||
} else {
|
||||
cfg.InheritParent = t
|
||||
}
|
||||
nt, err := t.tg.pidns.owner.NewTask(cfg)
|
||||
nt, err := t.tg.pidns.owner.NewTask(t, cfg)
|
||||
// If NewTask succeeds, we transfer references to nt. If NewTask fails, it does
|
||||
// the cleanup for us.
|
||||
cu.Release()
|
||||
if err != nil {
|
||||
if opts.NewThreadGroup {
|
||||
tg.release(t)
|
||||
}
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -286,7 +286,7 @@ func (*runExitMain) execute(t *Task) taskRunState {
|
||||
// If this is the last task to exit from the thread group, release the
|
||||
// thread group's resources.
|
||||
if lastExiter {
|
||||
t.tg.release(t)
|
||||
t.tg.Release(t)
|
||||
}
|
||||
|
||||
// Detach tracees.
|
||||
|
||||
@@ -16,6 +16,7 @@ package kernel
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/inet"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
@@ -98,15 +99,18 @@ type TaskConfig struct {
|
||||
// NewTask creates a new task defined by cfg.
|
||||
//
|
||||
// NewTask does not start the returned task; the caller must call Task.Start.
|
||||
func (ts *TaskSet) NewTask(cfg *TaskConfig) (*Task, error) {
|
||||
//
|
||||
// If successful, NewTask transfers references held by cfg to the new task.
|
||||
// Otherwise, NewTask releases them.
|
||||
func (ts *TaskSet) NewTask(ctx context.Context, cfg *TaskConfig) (*Task, error) {
|
||||
t, err := ts.newTask(cfg)
|
||||
if err != nil {
|
||||
cfg.TaskContext.release()
|
||||
cfg.FSContext.DecRef(t)
|
||||
cfg.FDTable.DecRef(t)
|
||||
cfg.IPCNamespace.DecRef(t)
|
||||
cfg.FSContext.DecRef(ctx)
|
||||
cfg.FDTable.DecRef(ctx)
|
||||
cfg.IPCNamespace.DecRef(ctx)
|
||||
if cfg.MountNamespaceVFS2 != nil {
|
||||
cfg.MountNamespaceVFS2.DecRef(t)
|
||||
cfg.MountNamespaceVFS2.DecRef(ctx)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"sync/atomic"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
@@ -307,8 +308,8 @@ func (tg *ThreadGroup) Limits() *limits.LimitSet {
|
||||
return tg.limits
|
||||
}
|
||||
|
||||
// release releases the thread group's resources.
|
||||
func (tg *ThreadGroup) release(t *Task) {
|
||||
// Release releases the thread group's resources.
|
||||
func (tg *ThreadGroup) Release(ctx context.Context) {
|
||||
// Timers must be destroyed without holding the TaskSet or signal mutexes
|
||||
// since timers send signals with Timer.mu locked.
|
||||
tg.itimerRealTimer.Destroy()
|
||||
@@ -325,7 +326,7 @@ func (tg *ThreadGroup) release(t *Task) {
|
||||
it.DestroyTimer()
|
||||
}
|
||||
if tg.mounts != nil {
|
||||
tg.mounts.DecRef(t)
|
||||
tg.mounts.DecRef(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user