aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/fs/exec.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2024-01-31 14:26:02 +0100
committerChristian Brauner <brauner@kernel.org>2024-02-02 13:12:28 +0100
commit64bef697d33b75fc06c5789b3f8108680271529f (patch)
treedacc56670ce9a76cb7252e69dd88fcdeb7d72f2f /fs/exec.c
parentpidfd: don't do_notify_pidfd() if !thread_group_empty() (diff)
downloadwireguard-linux-64bef697d33b75fc06c5789b3f8108680271529f.tar.xz
wireguard-linux-64bef697d33b75fc06c5789b3f8108680271529f.zip
pidfd: implement PIDFD_THREAD flag for pidfd_open()
With this flag: - pidfd_open() doesn't require that the target task must be a thread-group leader - pidfd_poll() succeeds when the task exits and becomes a zombie (iow, passes exit_notify()), even if it is a leader and thread-group is not empty. This means that the behaviour of pidfd_poll(PIDFD_THREAD, pid-of-group-leader) is not well defined if it races with exec() from its sub-thread; pidfd_poll() can succeed or not depending on whether pidfd_task_exited() is called before or after exchange_tids(). Perhaps we can improve this behaviour later, pidfd_poll() can probably take sig->group_exec_task into account. But this doesn't really differ from the case when the leader exits before other threads (so pidfd_poll() succeeds) and then another thread execs and pidfd_poll() will block again. thread_group_exited() is no longer used, perhaps it can die. Co-developed-by: Tycho Andersen <tycho@tycho.pizza> Signed-off-by: Oleg Nesterov <oleg@redhat.com> Link: https://lore.kernel.org/r/20240131132602.GA23641@redhat.com Tested-by: Tycho Andersen <tandersen@netflix.com> Reviewed-by: Tycho Andersen <tandersen@netflix.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 8cdd5b2dd09c..b68f61bbcaa8 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1143,7 +1143,11 @@ static int de_thread(struct task_struct *tsk)
BUG_ON(leader->exit_state != EXIT_ZOMBIE);
leader->exit_state = EXIT_DEAD;
-
+ /*
+ * leader and tsk exhanged their pids, the old pid dies,
+ * wake up the PIDFD_THREAD waiters.
+ */
+ do_notify_pidfd(leader);
/*
* We are going to release_task()->ptrace_unlink() silently,
* the tracer can sleep in do_wait(). EXIT_DEAD guarantees