diff options
author | Suren Baghdasaryan <[email protected]> | 2019-07-17 13:21:00 -0400 |
---|---|---|
committer | Christian Brauner <[email protected]> | 2019-07-22 16:02:03 +0200 |
commit | b191d6491be67cef2b3fa83015561caca1394ab9 (patch) | |
tree | 6be65f501b18e03aeb3c456f87a36b04dc45043b | |
parent | 5f9e832c137075045d15cd6899ab0505cfb2ca4b (diff) |
pidfd: fix a poll race when setting exit_state
There is a race between reading task->exit_state in pidfd_poll and
writing it after do_notify_parent calls do_notify_pidfd. Expected
sequence of events is:
CPU 0 CPU 1
------------------------------------------------
exit_notify
do_notify_parent
do_notify_pidfd
tsk->exit_state = EXIT_DEAD
pidfd_poll
if (tsk->exit_state)
However nothing prevents the following sequence:
CPU 0 CPU 1
------------------------------------------------
exit_notify
do_notify_parent
do_notify_pidfd
pidfd_poll
if (tsk->exit_state)
tsk->exit_state = EXIT_DEAD
This causes a polling task to wait forever, since poll blocks because
exit_state is 0 and the waiting task is not notified again. A stress
test continuously doing pidfd poll and process exits uncovered this bug.
To fix it, we make sure that the task's exit_state is always set before
calling do_notify_pidfd.
Fixes: b53b0b9d9a6 ("pidfd: add polling support")
Cc: [email protected]
Cc: Oleg Nesterov <[email protected]>
Signed-off-by: Suren Baghdasaryan <[email protected]>
Signed-off-by: Joel Fernandes (Google) <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
[[email protected]: adapt commit message and drop unneeded changes from wait_task_zombie]
Signed-off-by: Christian Brauner <[email protected]>
-rw-r--r-- | kernel/exit.c | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index a75b6a7f458a..4436158a6d30 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -720,6 +720,7 @@ static void exit_notify(struct task_struct *tsk, int group_dead) if (group_dead) kill_orphaned_pgrp(tsk->group_leader, NULL); + tsk->exit_state = EXIT_ZOMBIE; if (unlikely(tsk->ptrace)) { int sig = thread_group_leader(tsk) && thread_group_empty(tsk) && |