]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
pidfd: improve uapi when task isn't found
authorChristian Brauner <brauner@kernel.org>
Thu, 3 Apr 2025 14:09:03 +0000 (16:09 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 7 Apr 2025 07:38:24 +0000 (09:38 +0200)
We currently report EINVAL whenever a struct pid has no tasked attached
anymore thereby conflating two concepts:

(1) The task has already been reaped.
(2) The caller requested a pidfd for a thread-group leader but the pid
    actually references a struct pid that isn't used as a thread-group
    leader.

This is causing issues for non-threaded workloads as in [1].

This patch tries to allow userspace to distinguish between (1) and (2).
This is racy of course but that shouldn't matter.

Link: https://github.com/systemd/systemd/pull/36982
Link: https://lore.kernel.org/r/20250403-work-pidfd-fixes-v1-3-a123b6ed6716@kernel.org
Reviewed-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
kernel/fork.c

index 182ec2e9087d95329168636866fe7d7e2c417c95..4a2080b968c8eb098416d82ad1cd20dcca124e3f 100644 (file)
@@ -2108,10 +2108,27 @@ static int __pidfd_prepare(struct pid *pid, unsigned int flags, struct file **re
  */
 int pidfd_prepare(struct pid *pid, unsigned int flags, struct file **ret)
 {
-       bool thread = flags & PIDFD_THREAD;
+       int err = 0;
 
-       if (!pid_has_task(pid, thread ? PIDTYPE_PID : PIDTYPE_TGID))
-               return -EINVAL;
+       if (!(flags & PIDFD_THREAD)) {
+               /*
+                * If this is struct pid isn't used as a thread-group
+                * leader pid but the caller requested to create a
+                * thread-group leader pidfd then report ENOENT to the
+                * caller as a hint.
+                */
+               if (!pid_has_task(pid, PIDTYPE_TGID))
+                       err = -ENOENT;
+       }
+
+       /*
+        * If this wasn't a thread-group leader struct pid or the task
+        * got reaped in the meantime report -ESRCH to userspace.
+        */
+       if (!pid_has_task(pid, PIDTYPE_PID))
+               err = -ESRCH;
+       if (err)
+               return err;
 
        return __pidfd_prepare(pid, flags, ret);
 }