diff --git a/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go b/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go index 3bce26e90..c291a369f 100644 --- a/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go +++ b/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go @@ -511,6 +511,7 @@ type dir struct { kernfs.InodeNotSymlink kernfs.InodeWatches kernfs.OrderedChildren + kernfs.InodeFSOwned implStatFS locks vfs.FileLocks diff --git a/pkg/sentry/fsimpl/devpts/devpts.go b/pkg/sentry/fsimpl/devpts/devpts.go index ab6427e06..dc5b416fc 100644 --- a/pkg/sentry/fsimpl/devpts/devpts.go +++ b/pkg/sentry/fsimpl/devpts/devpts.go @@ -229,6 +229,7 @@ type rootInode struct { kernfs.InodeTemporary // This holds no meaning as this inode can't be Looked up and is always valid. kernfs.InodeWatches kernfs.OrderedChildren + kernfs.InodeFSOwned rootInodeRefs locks vfs.FileLocks diff --git a/pkg/sentry/fsimpl/devpts/master.go b/pkg/sentry/fsimpl/devpts/master.go index 5e0b8a8c7..498026fa6 100644 --- a/pkg/sentry/fsimpl/devpts/master.go +++ b/pkg/sentry/fsimpl/devpts/master.go @@ -39,6 +39,7 @@ type masterInode struct { kernfs.InodeNotAnonymous kernfs.InodeNotDirectory kernfs.InodeNotSymlink + kernfs.InodeFSOwned kernfs.InodeWatches locks vfs.FileLocks diff --git a/pkg/sentry/fsimpl/devpts/replica.go b/pkg/sentry/fsimpl/devpts/replica.go index fedfc23ff..e7af3512a 100644 --- a/pkg/sentry/fsimpl/devpts/replica.go +++ b/pkg/sentry/fsimpl/devpts/replica.go @@ -39,6 +39,7 @@ type replicaInode struct { kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches + kernfs.InodeFSOwned locks vfs.FileLocks diff --git a/pkg/sentry/fsimpl/fuse/inode.go b/pkg/sentry/fsimpl/fuse/inode.go index 09c74a5b6..9f026372d 100644 --- a/pkg/sentry/fsimpl/fuse/inode.go +++ b/pkg/sentry/fsimpl/fuse/inode.go @@ -50,6 +50,7 @@ type inode struct { kernfs.InodeWatches kernfs.OrderedChildren kernfs.CachedMappable + kernfs.InodeFSOwned // the owning filesystem. fs is immutable. fs *filesystem diff --git a/pkg/sentry/fsimpl/host/host.go b/pkg/sentry/fsimpl/host/host.go index 1b2cfd5e5..2aa0a7491 100644 --- a/pkg/sentry/fsimpl/host/host.go +++ b/pkg/sentry/fsimpl/host/host.go @@ -100,6 +100,7 @@ type inode struct { kernfs.InodeNotSymlink kernfs.InodeTemporary // This holds no meaning as this inode can't be Looked up and is always valid. kernfs.InodeWatches + kernfs.InodeFSOwned locks vfs.FileLocks diff --git a/pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go b/pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go index cae0a81f4..49770b554 100644 --- a/pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go +++ b/pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go @@ -42,6 +42,7 @@ type DynamicBytesFile struct { InodeNotDirectory InodeNotSymlink InodeWatches + InodeFSOwned locks vfs.FileLocks // data can additionally implement vfs.WritableDynamicBytesSource to support diff --git a/pkg/sentry/fsimpl/kernfs/filesystem.go b/pkg/sentry/fsimpl/kernfs/filesystem.go index 7caa2025d..b3b045bf0 100644 --- a/pkg/sentry/fsimpl/kernfs/filesystem.go +++ b/pkg/sentry/fsimpl/kernfs/filesystem.go @@ -155,6 +155,14 @@ func (fs *Filesystem) invalidateRemovedChildLocked(ctx context.Context, vfsObj * d := toInvalidate[len(toInvalidate)-1] toInvalidate = toInvalidate[:len(toInvalidate)-1] + if d.cached { + // The dentry is removed from the cache when its + // reference counter drops to 0. It can't be removed + // from the cache here, because fs.mu isn't locked for + // write. + d.IncRef() + fs.deferDecRef(d) + } if d.inode.Keep() { fs.deferDecRef(d) } diff --git a/pkg/sentry/fsimpl/kernfs/inode_impl_util.go b/pkg/sentry/fsimpl/kernfs/inode_impl_util.go index 3ec38cb82..07c5aac31 100644 --- a/pkg/sentry/fsimpl/kernfs/inode_impl_util.go +++ b/pkg/sentry/fsimpl/kernfs/inode_impl_util.go @@ -735,6 +735,7 @@ type StaticDirectory struct { InodeWatches OrderedChildren StaticDirectoryRefs + InodeFSOwned locks vfs.FileLocks fdOpts GenericDirectoryFDOptions @@ -845,3 +846,15 @@ type InodeNotAnonymous struct{} func (*InodeNotAnonymous) Anonymous() bool { return false } + +// InodeFSOwned represents inodes whose lifecycle is entirely managed by the +// filesystem. +// +// +stateify savable +type InodeFSOwned struct{} + +// RegisterDentry implements Inode.RegisterDentry. +func (*InodeFSOwned) RegisterDentry(d *Dentry) {} + +// UnregisterDentry implements Remove.UnregisterDentry. +func (*InodeFSOwned) UnregisterDentry(d *Dentry) {} diff --git a/pkg/sentry/fsimpl/kernfs/kernfs.go b/pkg/sentry/fsimpl/kernfs/kernfs.go index e197f6433..d7d600626 100644 --- a/pkg/sentry/fsimpl/kernfs/kernfs.go +++ b/pkg/sentry/fsimpl/kernfs/kernfs.go @@ -317,6 +317,27 @@ func (d *Dentry) decRefLocked(ctx context.Context) { } } +// Invalidate invalidates the dentry and its children. +func (d *Dentry) Invalidate(ctx context.Context) { + d.fs.mu.RLock() + defer d.fs.processDeferredDecRefs(ctx) + defer d.fs.mu.RUnlock() + parent := d.parent.Load() + if parent == nil { + return + } + parent.dirMu.Lock() + child := parent.children[d.name] + if child != d { + parent.dirMu.Unlock() + return + } + delete(parent.children, d.name) + parent.dirMu.Unlock() + + d.fs.invalidateRemovedChildLocked(ctx, d.fs.vfsfs.VirtualFilesystem(), child) +} + // cacheLocked should be called after d's reference count becomes 0. The ref // count check may happen before acquiring d.fs.mu so there might be a race // condition where the ref count is increased again by the time the caller @@ -451,6 +472,7 @@ func (d *Dentry) destroy(ctx context.Context) { panic("dentry.destroy() called with references on the dentry") } + d.inode.UnregisterDentry(d) d.inode.DecRef(ctx) // IncRef from Init. refs.Unregister(d) @@ -505,6 +527,7 @@ func (d *Dentry) Init(fs *Filesystem, inode Inode) { d.flags = atomicbitops.FromUint32(d.flags.RacyLoad() | dflagsIsSymlink) } refs.Register(d) + inode.RegisterDentry(d) } // VFSDentry returns the generic vfs dentry for this kernfs dentry. @@ -732,6 +755,13 @@ type Inode interface { // Anonymous indicates that the Inode is anonymous. It will never have // a name or parent. Anonymous() bool + + // RegisterDentry is called when a new dentry representing the inode is + // created. + RegisterDentry(d *Dentry) + + // UnregisterDentry is called when the specified dentry is destroyed. + UnregisterDentry(d *Dentry) } type inodeRefs interface { diff --git a/pkg/sentry/fsimpl/kernfs/kernfs_test.go b/pkg/sentry/fsimpl/kernfs/kernfs_test.go index e67537bda..6e487e3dd 100644 --- a/pkg/sentry/fsimpl/kernfs/kernfs_test.go +++ b/pkg/sentry/fsimpl/kernfs/kernfs_test.go @@ -109,6 +109,7 @@ type readonlyDir struct { kernfs.InodeTemporary kernfs.InodeWatches kernfs.OrderedChildren + kernfs.InodeFSOwned locks vfs.FileLocks } @@ -146,6 +147,7 @@ type dir struct { kernfs.InodeTemporary kernfs.InodeWatches kernfs.OrderedChildren + kernfs.InodeFSOwned locks vfs.FileLocks diff --git a/pkg/sentry/fsimpl/kernfs/symlink.go b/pkg/sentry/fsimpl/kernfs/symlink.go index 0c9a7b3a6..933da99d5 100644 --- a/pkg/sentry/fsimpl/kernfs/symlink.go +++ b/pkg/sentry/fsimpl/kernfs/symlink.go @@ -33,6 +33,7 @@ type StaticSymlink struct { InodeSymlink InodeNoStatFS InodeWatches + InodeFSOwned target string } diff --git a/pkg/sentry/fsimpl/kernfs/synthetic_directory.go b/pkg/sentry/fsimpl/kernfs/synthetic_directory.go index 4b28181d5..41700de43 100644 --- a/pkg/sentry/fsimpl/kernfs/synthetic_directory.go +++ b/pkg/sentry/fsimpl/kernfs/synthetic_directory.go @@ -37,6 +37,7 @@ type syntheticDirectory struct { InodeWatches OrderedChildren syntheticDirectoryRefs + InodeFSOwned locks vfs.FileLocks } diff --git a/pkg/sentry/fsimpl/mqfs/root.go b/pkg/sentry/fsimpl/mqfs/root.go index 7c26e2219..ecf01d500 100644 --- a/pkg/sentry/fsimpl/mqfs/root.go +++ b/pkg/sentry/fsimpl/mqfs/root.go @@ -36,6 +36,7 @@ type rootInode struct { kernfs.InodeTemporary kernfs.InodeWatches kernfs.OrderedChildren + kernfs.InodeFSOwned locks vfs.FileLocks } diff --git a/pkg/sentry/fsimpl/nsfs/nsfs.go b/pkg/sentry/fsimpl/nsfs/nsfs.go index 0d5dc2531..b4cb86820 100644 --- a/pkg/sentry/fsimpl/nsfs/nsfs.go +++ b/pkg/sentry/fsimpl/nsfs/nsfs.go @@ -83,6 +83,7 @@ type Inode struct { kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches + kernfs.InodeFSOwned inodeRefs locks vfs.FileLocks diff --git a/pkg/sentry/fsimpl/pipefs/pipefs.go b/pkg/sentry/fsimpl/pipefs/pipefs.go index 73e85654f..b332fdbfb 100644 --- a/pkg/sentry/fsimpl/pipefs/pipefs.go +++ b/pkg/sentry/fsimpl/pipefs/pipefs.go @@ -95,6 +95,7 @@ type inode struct { kernfs.InodeNotSymlink kernfs.InodeNoopRefCount kernfs.InodeWatches + kernfs.InodeFSOwned locks vfs.FileLocks pipe *pipe.VFSPipe diff --git a/pkg/sentry/fsimpl/proc/BUILD b/pkg/sentry/fsimpl/proc/BUILD index 794779d92..d4ca3b08e 100644 --- a/pkg/sentry/fsimpl/proc/BUILD +++ b/pkg/sentry/fsimpl/proc/BUILD @@ -1,3 +1,4 @@ +load("//pkg/sync/locking:locking.bzl", "declare_rwmutex") load("//tools:defs.bzl", "go_library", "go_test") load("//tools/go_generics:defs.bzl", "go_template_instance") @@ -60,9 +61,17 @@ go_template_instance( }, ) +declare_rwmutex( + name = "dentries_mutex", + out = "dentries_mutex.go", + package = "proc", + prefix = "dentries", +) + go_library( name = "proc", srcs = [ + "dentries_mutex.go", "fd_dir_inode_refs.go", "fd_info_dir_inode_refs.go", "filesystem.go", @@ -106,6 +115,7 @@ go_library( "//pkg/sentry/usage", "//pkg/sentry/vfs", "//pkg/sync", + "//pkg/sync/locking", "//pkg/tcpip/header", "//pkg/tcpip/network/ipv4", "//pkg/usermem", diff --git a/pkg/sentry/fsimpl/proc/subtasks.go b/pkg/sentry/fsimpl/proc/subtasks.go index 60e4dcb07..dab64758a 100644 --- a/pkg/sentry/fsimpl/proc/subtasks.go +++ b/pkg/sentry/fsimpl/proc/subtasks.go @@ -40,6 +40,7 @@ type subtasksInode struct { kernfs.InodeTemporary kernfs.InodeWatches kernfs.OrderedChildren + kernfs.InodeFSOwned subtasksInodeRefs locks vfs.FileLocks diff --git a/pkg/sentry/fsimpl/proc/task.go b/pkg/sentry/fsimpl/proc/task.go index d41a3c001..606553239 100644 --- a/pkg/sentry/fsimpl/proc/task.go +++ b/pkg/sentry/fsimpl/proc/task.go @@ -45,6 +45,10 @@ type taskInode struct { locks vfs.FileLocks task *kernel.Task + + dentriesMu dentriesRWMutex `state:"nosave"` + // dentries is a list of dentries to be invalidated when the task is destroyed. + dentries map[*kernfs.Dentry]struct{} } var _ kernfs.Inode = (*taskInode)(nil) @@ -99,7 +103,10 @@ func (fs *filesystem) newTaskInode(ctx context.Context, task *kernel.Task, pidns contents["cgroup"] = fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0444, &taskCgroupData{task: task}) } - taskInode := &taskInode{task: task} + taskInode := &taskInode{ + task: task, + dentries: make(map[*kernfs.Dentry]struct{}), + } // Note: credentials are overridden by taskOwnedInode. taskInode.InodeAttrs.Init(ctx, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555) taskInode.InitRefs() @@ -113,6 +120,44 @@ func (fs *filesystem) newTaskInode(ctx context.Context, task *kernel.Task, pidns return inode, nil } +func (i *taskInode) TaskDestroyAction(ctx context.Context) { + i.dentriesMu.Lock() + dentries := i.dentries + i.dentries = nil + i.dentriesMu.Unlock() + + for d := range dentries { + d.Invalidate(ctx) + } +} + +// RegisterDentry implements kernfs.Inode.RegisterDentry. +func (i *taskInode) RegisterDentry(d *kernfs.Dentry) { + i.dentriesMu.Lock() + defer i.dentriesMu.Unlock() + + if i.dentries == nil { + return + } + if len(i.dentries) == 0 && !i.task.RegisterOnDestroyAction(i) { + // The task has been destroyed. + i.dentries = nil + return + } + i.dentries[d] = struct{}{} +} + +// UnregisterDentry implements kernfs.Inode.RegisterDentry. +func (i *taskInode) UnregisterDentry(d *kernfs.Dentry) { + i.dentriesMu.Lock() + defer i.dentriesMu.Unlock() + + delete(i.dentries, d) + if len(i.dentries) == 0 { + i.task.UnregisterOnDestroyAction(i) + } +} + // Valid implements kernfs.Inode.Valid. This inode remains valid as long // as the task is still running. When it's dead, another tasks with the same // PID could replace it. @@ -141,6 +186,17 @@ func (i *taskInode) DecRef(ctx context.Context) { i.taskInodeRefs.DecRef(func() { i.Destroy(ctx) }) } +func (i *taskInode) Lookup(ctx context.Context, name string) (kernfs.Inode, error) { + i.dentriesMu.RLock() + if i.dentries == nil { + // The task has been destroyed and the inode invalidate callback has been executed. + i.dentriesMu.RUnlock() + return nil, linuxerr.ESRCH + } + i.dentriesMu.RUnlock() + return i.OrderedChildren.Lookup(ctx, name) +} + // taskOwnedInode implements kernfs.Inode and overrides inode owner with task // effective user and group. // diff --git a/pkg/sentry/fsimpl/proc/task_fds.go b/pkg/sentry/fsimpl/proc/task_fds.go index 83996a446..14ad5d093 100644 --- a/pkg/sentry/fsimpl/proc/task_fds.go +++ b/pkg/sentry/fsimpl/proc/task_fds.go @@ -118,6 +118,7 @@ type fdDirInode struct { kernfs.InodeTemporary kernfs.InodeWatches kernfs.OrderedChildren + kernfs.InodeFSOwned } var _ kernfs.Inode = (*fdDirInode)(nil) @@ -202,6 +203,7 @@ type fdSymlink struct { kernfs.InodeNotAnonymous kernfs.InodeSymlink kernfs.InodeWatches + kernfs.InodeFSOwned fs *filesystem task *kernel.Task @@ -264,6 +266,7 @@ type fdInfoDirInode struct { kernfs.InodeTemporary kernfs.InodeWatches kernfs.OrderedChildren + kernfs.InodeFSOwned } var _ kernfs.Inode = (*fdInfoDirInode)(nil) diff --git a/pkg/sentry/fsimpl/proc/task_files.go b/pkg/sentry/fsimpl/proc/task_files.go index c0d818b47..366d9476a 100644 --- a/pkg/sentry/fsimpl/proc/task_files.go +++ b/pkg/sentry/fsimpl/proc/task_files.go @@ -422,6 +422,7 @@ type memInode struct { kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches + kernfs.InodeFSOwned task *kernel.Task locks vfs.FileLocks @@ -743,6 +744,7 @@ type statusInode struct { kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches + kernfs.InodeFSOwned task *kernel.Task pidns *kernel.PIDNamespace @@ -981,6 +983,7 @@ type exeSymlink struct { kernfs.InodeNotAnonymous kernfs.InodeSymlink kernfs.InodeWatches + kernfs.InodeFSOwned fs *filesystem task *kernel.Task @@ -1054,6 +1057,7 @@ type cwdSymlink struct { kernfs.InodeNotAnonymous kernfs.InodeSymlink kernfs.InodeWatches + kernfs.InodeFSOwned fs *filesystem task *kernel.Task @@ -1116,6 +1120,7 @@ type rootSymlink struct { kernfs.InodeNotAnonymous kernfs.InodeSymlink kernfs.InodeWatches + kernfs.InodeFSOwned fs *filesystem task *kernel.Task @@ -1360,6 +1365,7 @@ type namespaceInode struct { kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches + kernfs.InodeFSOwned locks vfs.FileLocks } diff --git a/pkg/sentry/fsimpl/proc/tasks.go b/pkg/sentry/fsimpl/proc/tasks.go index e4948791c..68dac3160 100644 --- a/pkg/sentry/fsimpl/proc/tasks.go +++ b/pkg/sentry/fsimpl/proc/tasks.go @@ -46,6 +46,7 @@ type tasksInode struct { kernfs.InodeTemporary // This holds no meaning as this inode can't be Looked up and is always valid. kernfs.InodeWatches kernfs.OrderedChildren + kernfs.InodeFSOwned tasksInodeRefs locks vfs.FileLocks diff --git a/pkg/sentry/fsimpl/proc/tasks_files.go b/pkg/sentry/fsimpl/proc/tasks_files.go index 97eef2917..1febbbc5b 100644 --- a/pkg/sentry/fsimpl/proc/tasks_files.go +++ b/pkg/sentry/fsimpl/proc/tasks_files.go @@ -40,6 +40,7 @@ type selfSymlink struct { kernfs.InodeNotAnonymous kernfs.InodeSymlink kernfs.InodeWatches + kernfs.InodeFSOwned pidns *kernel.PIDNamespace } @@ -83,6 +84,7 @@ type threadSelfSymlink struct { kernfs.InodeNotAnonymous kernfs.InodeSymlink kernfs.InodeWatches + kernfs.InodeFSOwned pidns *kernel.PIDNamespace } diff --git a/pkg/sentry/fsimpl/sockfs/sockfs.go b/pkg/sentry/fsimpl/sockfs/sockfs.go index 455481447..3e3f01cf2 100644 --- a/pkg/sentry/fsimpl/sockfs/sockfs.go +++ b/pkg/sentry/fsimpl/sockfs/sockfs.go @@ -100,6 +100,7 @@ type inode struct { kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches + kernfs.InodeFSOwned } // Open implements kernfs.Inode.Open. diff --git a/pkg/sentry/fsimpl/sys/kcov.go b/pkg/sentry/fsimpl/sys/kcov.go index f71313543..1d6afcd95 100644 --- a/pkg/sentry/fsimpl/sys/kcov.go +++ b/pkg/sentry/fsimpl/sys/kcov.go @@ -43,6 +43,7 @@ type kcovInode struct { kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches + kernfs.InodeFSOwned implStatFS } diff --git a/pkg/sentry/fsimpl/sys/sys.go b/pkg/sentry/fsimpl/sys/sys.go index 2c3efd0af..cffb0bfaf 100644 --- a/pkg/sentry/fsimpl/sys/sys.go +++ b/pkg/sentry/fsimpl/sys/sys.go @@ -383,6 +383,7 @@ type dir struct { kernfs.InodeNotSymlink kernfs.InodeTemporary kernfs.InodeWatches + kernfs.InodeFSOwned kernfs.OrderedChildren locks vfs.FileLocks diff --git a/pkg/sentry/kernel/task.go b/pkg/sentry/kernel/task.go index 0c65b1828..7d62227ff 100644 --- a/pkg/sentry/kernel/task.go +++ b/pkg/sentry/kernel/task.go @@ -630,6 +630,10 @@ type Task struct { // Origin is the origin of the task. Origin TaskOrigin + + // onDestroyAction is a set of callbacks that are executed when the + // task is destroyed. + onDestroyAction map[TaskDestroyAction]struct{} } // Task related metrics diff --git a/pkg/sentry/kernel/task_exit.go b/pkg/sentry/kernel/task_exit.go index 0e8ac8067..38cc377cb 100644 --- a/pkg/sentry/kernel/task_exit.go +++ b/pkg/sentry/kernel/task_exit.go @@ -30,6 +30,7 @@ import ( "strconv" "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/sentry/kernel/auth" @@ -756,9 +757,58 @@ func (t *Task) exitNotifyLocked(fromPtraceDetach bool) { // Do not clear t.parent. It may be still be needed after the task has exited // (for example, to perform ptrace access checks on /proc/[pid] files). } + t.execOnDestroyActions() } } +// TaskDestroyAction defines an action to be executed when a task is destroyed. +type TaskDestroyAction interface { + TaskDestroyAction(ctx context.Context) +} + +// RegisterOnDestroyAction registers an action to be executed when the task +// is destroyed. +// +// It returns true if the action was successfully registered. +// If the task is already terminated, it returns false. +func (t *Task) RegisterOnDestroyAction(act TaskDestroyAction) bool { + t.mu.Lock() + defer t.mu.Unlock() + if t.onDestroyAction == nil { + return false + } + t.onDestroyAction[act] = struct{}{} + return true +} + +// UnregisterOnDestroyAction unregisters an action previously registered with +// RegisterOnDestroyAction. +func (t *Task) UnregisterOnDestroyAction(key TaskDestroyAction) { + t.mu.Lock() + defer t.mu.Unlock() + delete(t.onDestroyAction, key) +} + +func (t *Task) execOnDestroyActions() { + t.mu.Lock() + actions := t.onDestroyAction + t.onDestroyAction = nil + t.mu.Unlock() + + if len(actions) == 0 { + return + } + // Block S/R until all actions is executed. + t.k.tasks.aioGoroutines.Add(1) + // Run in another goroutine to avoid extra lock dependencies. + go func() { + defer t.k.tasks.aioGoroutines.Done() + for act := range actions { + act.TaskDestroyAction(t) + } + }() +} + // Preconditions: The TaskSet mutex must be locked. func (t *Task) exitNotificationSignal(sig linux.Signal, receiver *Task) *linux.SignalInfo { info := &linux.SignalInfo{ diff --git a/pkg/sentry/kernel/task_start.go b/pkg/sentry/kernel/task_start.go index 84260ba1e..c7616ee9b 100644 --- a/pkg/sentry/kernel/task_start.go +++ b/pkg/sentry/kernel/task_start.go @@ -151,30 +151,31 @@ func (ts *TaskSet) newTask(ctx context.Context, cfg *TaskConfig) (*Task, error) parent: cfg.Parent, children: make(map[*Task]struct{}), }, - runState: (*runApp)(nil), - interruptChan: make(chan struct{}, 1), - signalMask: atomicbitops.FromUint64(uint64(cfg.SignalMask)), - signalStack: linux.SignalStack{Flags: linux.SS_DISABLE}, - image: *image, - fsContext: cfg.FSContext, - fdTable: cfg.FDTable, - k: cfg.Kernel, - ptraceTracees: make(map[*Task]struct{}), - allowedCPUMask: cfg.AllowedCPUMask.Copy(), - ioUsage: &usage.IO{}, - niceness: cfg.Niceness, - utsns: cfg.UTSNamespace, - ipcns: cfg.IPCNamespace, - mountNamespace: cfg.MountNamespace, - rseqCPU: -1, - rseqAddr: cfg.RSeqAddr, - rseqSignature: cfg.RSeqSignature, - futexWaiter: futex.NewWaiter(), - containerID: cfg.ContainerID, - cgroups: make(map[Cgroup]struct{}), - userCounters: cfg.UserCounters, - sessionKeyring: cfg.SessionKeyring, - Origin: cfg.Origin, + runState: (*runApp)(nil), + interruptChan: make(chan struct{}, 1), + signalMask: atomicbitops.FromUint64(uint64(cfg.SignalMask)), + signalStack: linux.SignalStack{Flags: linux.SS_DISABLE}, + image: *image, + fsContext: cfg.FSContext, + fdTable: cfg.FDTable, + k: cfg.Kernel, + ptraceTracees: make(map[*Task]struct{}), + allowedCPUMask: cfg.AllowedCPUMask.Copy(), + ioUsage: &usage.IO{}, + niceness: cfg.Niceness, + utsns: cfg.UTSNamespace, + ipcns: cfg.IPCNamespace, + mountNamespace: cfg.MountNamespace, + rseqCPU: -1, + rseqAddr: cfg.RSeqAddr, + rseqSignature: cfg.RSeqSignature, + futexWaiter: futex.NewWaiter(), + containerID: cfg.ContainerID, + cgroups: make(map[Cgroup]struct{}), + userCounters: cfg.UserCounters, + sessionKeyring: cfg.SessionKeyring, + Origin: cfg.Origin, + onDestroyAction: make(map[TaskDestroyAction]struct{}), } t.netns = cfg.NetworkNamespace t.creds.Store(cfg.Credentials)