]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
af_unix: stash pidfs dentry when needed
authorAlexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Thu, 3 Jul 2025 22:23:09 +0000 (00:23 +0200)
committerChristian Brauner <brauner@kernel.org>
Fri, 4 Jul 2025 07:32:35 +0000 (09:32 +0200)
We need to ensure that pidfs dentry is allocated when we meet any
struct pid for the first time. This will allows us to open pidfd
even after the task it corresponds to is reaped.

Basically, we need to identify all places where we fill skb/scm_cookie
with struct pid reference for the first time and call pidfs_register_pid().

Tricky thing here is that we have a few places where this happends
depending on what userspace is doing:
- [__scm_replace_pid()] explicitly sending an SCM_CREDENTIALS message
                        and specified pid in a numeric format
- [unix_maybe_add_creds()] enabled SO_PASSCRED/SO_PASSPIDFD but
                           didn't send SCM_CREDENTIALS explicitly
- [scm_send()] force_creds is true. Netlink case, we don't need to touch it.

Cc: linux-kernel@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: David S. Miller <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Simon Horman <horms@kernel.org>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Kuniyuki Iwashima <kuniyu@google.com>
Cc: Lennart Poettering <mzxreary@0pointer.de>
Cc: Luca Boccassi <bluca@debian.org>
Cc: David Rheinsberg <david@readahead.eu>
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Link: https://lore.kernel.org/20250703222314.309967-6-aleksandr.mikhalitsyn@canonical.com
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
net/core/scm.c
net/unix/af_unix.c

index 045ab5bdac7d1640d980a4b3b39b2403df8f414a..358a4e04d46cfc3582e597ca589b06d092c606c2 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/security.h>
 #include <linux/pid_namespace.h>
 #include <linux/pid.h>
+#include <linux/pidfs.h>
 #include <linux/nsproxy.h>
 #include <linux/slab.h>
 #include <linux/errqueue.h>
@@ -147,9 +148,15 @@ EXPORT_SYMBOL(__scm_destroy);
 
 static inline int scm_replace_pid(struct scm_cookie *scm, struct pid *pid)
 {
+       int err;
+
        /* drop all previous references */
        scm_destroy_cred(scm);
 
+       err = pidfs_register_pid(pid);
+       if (unlikely(err))
+               return err;
+
        scm->pid = pid;
        scm->creds.pid = pid_vnr(pid);
        return 0;
index 323e4fc85d4bc53ecc482f5b4b5ef5421130c1ce..d52811321fceafb4498eb2928284c4b7b7700678 100644 (file)
@@ -1971,6 +1971,7 @@ static void unix_skb_to_scm(struct sk_buff *skb, struct scm_cookie *scm)
  * We include credentials if source or destination socket
  * asserted SOCK_PASSCRED.
  *
+ * Context: May sleep.
  * Return: On success zero, on error a negative error code is returned.
  */
 static int unix_maybe_add_creds(struct sk_buff *skb, const struct sock *sk,
@@ -1980,7 +1981,15 @@ static int unix_maybe_add_creds(struct sk_buff *skb, const struct sock *sk,
                return 0;
 
        if (unix_may_passcred(sk) || unix_may_passcred(other)) {
-               UNIXCB(skb).pid = get_pid(task_tgid(current));
+               struct pid *pid;
+               int err;
+
+               pid = task_tgid(current);
+               err = pidfs_register_pid(pid);
+               if (unlikely(err))
+                       return err;
+
+               UNIXCB(skb).pid = get_pid(pid);
                current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
        }