Skip to content

Commit 0c9bd6b

Browse files
tych0brauner
authored andcommitted
pidfd: getfd should always report ESRCH if a task is exiting
We can get EBADF from pidfd_getfd() if a task is currently exiting, which might be confusing. Let's check PF_EXITING, and just report ESRCH if so. I chose PF_EXITING, because it is set in exit_signals(), which is called before exit_files(). Since ->exit_status is mostly set after exit_files() in exit_notify(), using that still leaves a window open for the race. Reviewed-by: Oleg Nesterov <[email protected]> Signed-off-by: Tycho Andersen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 83b290c commit 0c9bd6b

File tree

1 file changed

+20
-1
lines changed

1 file changed

+20
-1
lines changed

kernel/pid.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,26 @@ static struct file *__pidfd_fget(struct task_struct *task, int fd)
678678

679679
up_read(&task->signal->exec_update_lock);
680680

681-
return file ?: ERR_PTR(-EBADF);
681+
if (!file) {
682+
/*
683+
* It is possible that the target thread is exiting; it can be
684+
* either:
685+
* 1. before exit_signals(), which gives a real fd
686+
* 2. before exit_files() takes the task_lock() gives a real fd
687+
* 3. after exit_files() releases task_lock(), ->files is NULL;
688+
* this has PF_EXITING, since it was set in exit_signals(),
689+
* __pidfd_fget() returns EBADF.
690+
* In case 3 we get EBADF, but that really means ESRCH, since
691+
* the task is currently exiting and has freed its files
692+
* struct, so we fix it up.
693+
*/
694+
if (task->flags & PF_EXITING)
695+
file = ERR_PTR(-ESRCH);
696+
else
697+
file = ERR_PTR(-EBADF);
698+
}
699+
700+
return file;
682701
}
683702

684703
static int pidfd_getfd(struct pid *pid, int fd)

0 commit comments

Comments
 (0)