diff --git a/pkg/sentry/fsimpl/proc/task_fds.go b/pkg/sentry/fsimpl/proc/task_fds.go index 8289b2ef6..94ed13bec 100644 --- a/pkg/sentry/fsimpl/proc/task_fds.go +++ b/pkg/sentry/fsimpl/proc/task_fds.go @@ -43,12 +43,13 @@ func getTaskFD(t *kernel.Task, fd int32) (*vfs.FileDescription, kernel.FDFlags) } func taskFDExists(ctx context.Context, fs *filesystem, t *kernel.Task, fd int32) bool { - file, _ := getTaskFD(t, fd) - if file == nil { - return false - } - fs.SafeDecRefFD(ctx, file) - return true + var exists bool + t.WithMuLocked(func(task *kernel.Task) { + if fdt := t.FDTable(); fdt != nil { + exists = fdt.Exists(fd) + } + }) + return exists } // +stateify savable diff --git a/pkg/sentry/kernel/fd_table.go b/pkg/sentry/kernel/fd_table.go index f9e31a9c1..a8cdc38a3 100644 --- a/pkg/sentry/kernel/fd_table.go +++ b/pkg/sentry/kernel/fd_table.go @@ -440,6 +440,17 @@ func (f *FDTable) GetFDs(ctx context.Context) []int32 { return fds } +// Exists returns whether fd is defined in the table. It is inherently racy. +// +//go:nosplit +func (f *FDTable) Exists(fd int32) bool { + if fd < 0 { + return false + } + file, _, _ := f.get(fd) + return file != nil +} + // Fork returns an independent FDTable, cloning all FDs up to maxFds (non-inclusive). func (f *FDTable) Fork(ctx context.Context, maxFds int32) *FDTable { clone := f.k.NewFDTable()