* [PATCH RFC 0/4] net, pidfs: enable handing out pidfds for reaped sk->sk_peer_pid
@ 2025-04-24 12:24 Christian Brauner
2025-04-24 12:24 ` [PATCH RFC 1/4] pidfs: register pid in pidfs Christian Brauner
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Christian Brauner @ 2025-04-24 12:24 UTC (permalink / raw)
To: Oleg Nesterov, Kuniyuki Iwashima, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: linux-kernel, linux-fsdevel, netdev, David Rheinsberg, Jan Kara,
Alexander Mikhalitsyn, Luca Boccassi, Lennart Poettering,
Daan De Meyer, Mike Yuan, Christian Brauner
SO_PEERPIDFD currently doesn't support handing out pidfds if the
sk->sk_peer_pid thread-group leader has already been reaped. In this
case it currently returns EINVAL. Userspace still wants to get a pidfd
for a reaped process to have a stable handle it can pass on.
This is especially useful now that it is possible to retrieve exit
information through a pidfd via the PIDFD_GET_INFO ioctl()'s
PIDFD_INFO_EXIT flag.
Another summary has been provided by David in [1]:
> A pidfd can outlive the task it refers to, and thus user-space must
> already be prepared that the task underlying a pidfd is gone at the time
> they get their hands on the pidfd. For instance, resolving the pidfd to
> a PID via the fdinfo must be prepared to read `-1`.
>
> Despite user-space knowing that a pidfd might be stale, several kernel
> APIs currently add another layer that checks for this. In particular,
> SO_PEERPIDFD returns `EINVAL` if the peer-task was already reaped,
> but returns a stale pidfd if the task is reaped immediately after the
> respective alive-check.
>
> This has the unfortunate effect that user-space now has two ways to
> check for the exact same scenario: A syscall might return
> EINVAL/ESRCH/... *or* the pidfd might be stale, even though there is no
> particular reason to distinguish both cases. This also propagates
> through user-space APIs, which pass on pidfds. They must be prepared to
> pass on `-1` *or* the pidfd, because there is no guaranteed way to get a
> stale pidfd from the kernel.
> Userspace must already deal with a pidfd referring to a reaped task as
> the task may exit and get reaped at any time will there are still many
> pidfds referring to it.
In order to allow handing out reaped pidfd SO_PEERPIDFD needs to ensure
that PIDFD_INFO_EXIT information is available whenever a pidfd for a
reaped task is created by PIDFD_INFO_EXIT. The uapi promises that reaped
pidfds are only handed out if it is guaranteed that the caller sees the
exit information:
TEST_F(pidfd_info, success_reaped)
{
struct pidfd_info info = {
.mask = PIDFD_INFO_CGROUPID | PIDFD_INFO_EXIT,
};
/*
* Process has already been reaped and PIDFD_INFO_EXIT been set.
* Verify that we can retrieve the exit status of the process.
*/
ASSERT_EQ(ioctl(self->child_pidfd4, PIDFD_GET_INFO, &info), 0);
ASSERT_FALSE(!!(info.mask & PIDFD_INFO_CREDS));
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_EXIT));
ASSERT_TRUE(WIFEXITED(info.exit_code));
ASSERT_EQ(WEXITSTATUS(info.exit_code), 0);
}
To hand out pidfds for reaped processes we thus allocate a pidfs entry
for the relevant sk->sk_peer_pid at the time the sk->sk_peer_pid is
stashed and drop it when the socket is destroyed. This guarantees that
exit information will always be recorded for the sk->sk_peer_pid task
and we can hand out pidfds for reaped processes.
Note, I'm marking this as RFC mostly because I'm open to other
approaches to solving the pidfs registration. The functionality in
general we should really provide either way.
Link: https://lore.kernel.org/lkml/20230807085203.819772-1-david@readahead.eu [1]
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
Christian Brauner (4):
pidfs: register pid in pidfs
net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid
pidfs: get rid of __pidfd_prepare()
net, pidfs: enable handing out pidfds for reaped sk->sk_peer_pid
fs/pidfs.c | 70 ++++++++++++++++++++++++++++++++----
include/linux/pidfs.h | 3 ++
include/uapi/linux/pidfd.h | 2 +-
kernel/fork.c | 78 +++++++++++++---------------------------
net/core/sock.c | 4 ++-
net/unix/af_unix.c | 90 ++++++++++++++++++++++++++++++++++++++++------
6 files changed, 174 insertions(+), 73 deletions(-)
---
base-commit: b590c928cca7bdc7fd580d52e42bfdc3ac5eeacb
change-id: 20250423-work-pidfs-net-bc0181263d38
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RFC 1/4] pidfs: register pid in pidfs
2025-04-24 12:24 [PATCH RFC 0/4] net, pidfs: enable handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
@ 2025-04-24 12:24 ` Christian Brauner
2025-04-24 13:24 ` Oleg Nesterov
2025-04-24 12:24 ` [PATCH RFC 2/4] net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
` (2 subsequent siblings)
3 siblings, 1 reply; 13+ messages in thread
From: Christian Brauner @ 2025-04-24 12:24 UTC (permalink / raw)
To: Oleg Nesterov, Kuniyuki Iwashima, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: linux-kernel, linux-fsdevel, netdev, David Rheinsberg, Jan Kara,
Alexander Mikhalitsyn, Luca Boccassi, Lennart Poettering,
Daan De Meyer, Mike Yuan, Christian Brauner
Add simple helpers that allow a struct pid to be pinned via a pidfs
dentry/inode. If no pidfs dentry exists a new one will be allocated for
it. A reference is taken by pidfs on @pid. The reference must be
released via pidfs_put_pid().
This will allow AF_UNIX sockets to allocate a dentry for the peer
credentials pid at the time they are recorded where we know the task is
still alive. When the task gets reaped its exit status is guaranteed to
be recorded and a pidfd can be handed for the reaped task.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/pidfs.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/pidfs.h | 3 +++
2 files changed, 61 insertions(+)
diff --git a/fs/pidfs.c b/fs/pidfs.c
index d64a4cbeb0da..8e6c11774c60 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -896,6 +896,64 @@ struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags)
return pidfd_file;
}
+/**
+ * pidfs_register_pid - pin a struct pid through pidfs
+ * @pid: pid to pin
+ *
+ * Pin a struct pid through pidfs. Needs to be paired with
+ * pidfds_put_put() to not risk leaking the pidfs dentry and inode.
+ *
+ * Return: On success zero, on error a negative error code is returned.
+ */
+int pidfs_register_pid(struct pid *pid)
+{
+ struct path path __free(path_put) = {};
+ int ret;
+
+ might_sleep();
+
+ if (!pid)
+ return 0;
+
+ ret = path_from_stashed(&pid->stashed, pidfs_mnt, get_pid(pid), &path);
+ if (unlikely(ret))
+ return ret;
+ path.dentry = NULL;
+ return 0;
+}
+
+/**
+ * pidfs_get_pid - pin a struct pid through pidfs
+ * @pid: pid to pin
+ *
+ * Similar to pidfs_register_pid() but only valid if the caller knows
+ * there's a reference to the @pid through its dentry already.
+ */
+void pidfs_get_pid(struct pid *pid)
+{
+ if (!pid)
+ return;
+
+ WARN_ON_ONCE(stashed_dentry_get(&pid->stashed) == NULL);
+}
+
+/**
+ * pidfs_put_pid - drop a pidfs reference
+ * @pid: pid to drop
+ *
+ * Drop a reference to @pid via pidfs. This is only safe if the
+ * reference has been taken via pidfs_get_pid().
+ */
+void pidfs_put_pid(struct pid *pid)
+{
+ might_sleep();
+
+ if (!pid)
+ return;
+
+ dput(pid->stashed);
+}
+
static void pidfs_inode_init_once(void *data)
{
struct pidfs_inode *pi = data;
diff --git a/include/linux/pidfs.h b/include/linux/pidfs.h
index 05e6f8f4a026..2676890c4d0d 100644
--- a/include/linux/pidfs.h
+++ b/include/linux/pidfs.h
@@ -8,5 +8,8 @@ void pidfs_add_pid(struct pid *pid);
void pidfs_remove_pid(struct pid *pid);
void pidfs_exit(struct task_struct *tsk);
extern const struct dentry_operations pidfs_dentry_operations;
+int pidfs_register_pid(struct pid *pid);
+void pidfs_get_pid(struct pid *pid);
+void pidfs_put_pid(struct pid *pid);
#endif /* _LINUX_PID_FS_H */
--
2.47.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 2/4] net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid
2025-04-24 12:24 [PATCH RFC 0/4] net, pidfs: enable handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
2025-04-24 12:24 ` [PATCH RFC 1/4] pidfs: register pid in pidfs Christian Brauner
@ 2025-04-24 12:24 ` Christian Brauner
2025-04-24 12:44 ` David Rheinsberg
2025-04-25 1:57 ` Kuniyuki Iwashima
2025-04-24 12:24 ` [PATCH RFC 3/4] pidfs: get rid of __pidfd_prepare() Christian Brauner
2025-04-24 12:24 ` [PATCH RFC 4/4] net, pidfs: enable handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
3 siblings, 2 replies; 13+ messages in thread
From: Christian Brauner @ 2025-04-24 12:24 UTC (permalink / raw)
To: Oleg Nesterov, Kuniyuki Iwashima, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: linux-kernel, linux-fsdevel, netdev, David Rheinsberg, Jan Kara,
Alexander Mikhalitsyn, Luca Boccassi, Lennart Poettering,
Daan De Meyer, Mike Yuan, Christian Brauner
SO_PEERPIDFD currently doesn't support handing out pidfds if the
sk->sk_peer_pid thread-group leader has already been reaped. In this
case it currently returns EINVAL. Userspace still wants to get a pidfd
for a reaped process to have a stable handle it can pass on.
This is especially useful now that it is possible to retrieve exit
information through a pidfd via the PIDFD_GET_INFO ioctl()'s
PIDFD_INFO_EXIT flag.
Another summary has been provided by David in [1]:
> A pidfd can outlive the task it refers to, and thus user-space must
> already be prepared that the task underlying a pidfd is gone at the time
> they get their hands on the pidfd. For instance, resolving the pidfd to
> a PID via the fdinfo must be prepared to read `-1`.
>
> Despite user-space knowing that a pidfd might be stale, several kernel
> APIs currently add another layer that checks for this. In particular,
> SO_PEERPIDFD returns `EINVAL` if the peer-task was already reaped,
> but returns a stale pidfd if the task is reaped immediately after the
> respective alive-check.
>
> This has the unfortunate effect that user-space now has two ways to
> check for the exact same scenario: A syscall might return
> EINVAL/ESRCH/... *or* the pidfd might be stale, even though there is no
> particular reason to distinguish both cases. This also propagates
> through user-space APIs, which pass on pidfds. They must be prepared to
> pass on `-1` *or* the pidfd, because there is no guaranteed way to get a
> stale pidfd from the kernel.
> Userspace must already deal with a pidfd referring to a reaped task as
> the task may exit and get reaped at any time will there are still many
> pidfds referring to it.
In order to allow handing out reaped pidfd SO_PEERPIDFD needs to ensure
that PIDFD_INFO_EXIT information is available whenever a pidfd for a
reaped task is created by PIDFD_INFO_EXIT. The uapi promises that reaped
pidfds are only handed out if it is guaranteed that the caller sees the
exit information:
TEST_F(pidfd_info, success_reaped)
{
struct pidfd_info info = {
.mask = PIDFD_INFO_CGROUPID | PIDFD_INFO_EXIT,
};
/*
* Process has already been reaped and PIDFD_INFO_EXIT been set.
* Verify that we can retrieve the exit status of the process.
*/
ASSERT_EQ(ioctl(self->child_pidfd4, PIDFD_GET_INFO, &info), 0);
ASSERT_FALSE(!!(info.mask & PIDFD_INFO_CREDS));
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_EXIT));
ASSERT_TRUE(WIFEXITED(info.exit_code));
ASSERT_EQ(WEXITSTATUS(info.exit_code), 0);
}
To hand out pidfds for reaped processes we thus allocate a pidfs entry
for the relevant sk->sk_peer_pid at the time the sk->sk_peer_pid is
stashed and drop it when the socket is destroyed. This guarantees that
exit information will always be recorded for the sk->sk_peer_pid task
and we can hand out pidfds for reaped processes.
Link: https://lore.kernel.org/lkml/20230807085203.819772-1-david@readahead.eu [1]
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
net/unix/af_unix.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 79 insertions(+), 11 deletions(-)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index f78a2492826f..83b5aebf499e 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -100,6 +100,7 @@
#include <linux/splice.h>
#include <linux/string.h>
#include <linux/uaccess.h>
+#include <linux/pidfs.h>
#include <net/af_unix.h>
#include <net/net_namespace.h>
#include <net/scm.h>
@@ -643,6 +644,14 @@ static void unix_sock_destructor(struct sock *sk)
return;
}
+ if (sock_flag(sk, SOCK_RCU_FREE)) {
+ pr_info("Attempting to release RCU protected socket with sleeping locks: %p\n", sk);
+ return;
+ }
+
+ if (sk->sk_peer_pid)
+ pidfs_put_pid(sk->sk_peer_pid);
+
if (u->addr)
unix_release_addr(u->addr);
@@ -734,13 +743,48 @@ static void unix_release_sock(struct sock *sk, int embrion)
unix_gc(); /* Garbage collect fds */
}
-static void init_peercred(struct sock *sk)
+struct af_unix_peercred {
+ struct pid *peer_pid;
+ const struct cred *peer_cred;
+};
+
+static inline int prepare_peercred(struct af_unix_peercred *peercred)
+{
+ struct pid *pid;
+ int err;
+
+ pid = task_tgid(current);
+ err = pidfs_register_pid(pid);
+ if (likely(!err)) {
+ peercred->peer_pid = get_pid(pid);
+ peercred->peer_cred = get_current_cred();
+ }
+ return err;
+}
+
+static void drop_peercred(struct af_unix_peercred *peercred)
+{
+ struct pid *pid = NULL;
+ const struct cred *cred = NULL;
+
+ might_sleep();
+
+ swap(peercred->peer_pid, pid);
+ swap(peercred->peer_cred, cred);
+
+ pidfs_put_pid(pid);
+ put_pid(pid);
+ put_cred(cred);
+}
+
+static inline void init_peercred(struct sock *sk,
+ const struct af_unix_peercred *peercred)
{
- sk->sk_peer_pid = get_pid(task_tgid(current));
- sk->sk_peer_cred = get_current_cred();
+ sk->sk_peer_pid = peercred->peer_pid;
+ sk->sk_peer_cred = peercred->peer_cred;
}
-static void update_peercred(struct sock *sk)
+static void update_peercred(struct sock *sk, struct af_unix_peercred *peercred)
{
const struct cred *old_cred;
struct pid *old_pid;
@@ -748,11 +792,11 @@ static void update_peercred(struct sock *sk)
spin_lock(&sk->sk_peer_lock);
old_pid = sk->sk_peer_pid;
old_cred = sk->sk_peer_cred;
- init_peercred(sk);
+ init_peercred(sk, peercred);
spin_unlock(&sk->sk_peer_lock);
- put_pid(old_pid);
- put_cred(old_cred);
+ peercred->peer_pid = old_pid;
+ peercred->peer_cred = old_cred;
}
static void copy_peercred(struct sock *sk, struct sock *peersk)
@@ -761,6 +805,7 @@ static void copy_peercred(struct sock *sk, struct sock *peersk)
spin_lock(&sk->sk_peer_lock);
sk->sk_peer_pid = get_pid(peersk->sk_peer_pid);
+ pidfs_get_pid(sk->sk_peer_pid);
sk->sk_peer_cred = get_cred(peersk->sk_peer_cred);
spin_unlock(&sk->sk_peer_lock);
}
@@ -770,6 +815,7 @@ static int unix_listen(struct socket *sock, int backlog)
int err;
struct sock *sk = sock->sk;
struct unix_sock *u = unix_sk(sk);
+ struct af_unix_peercred peercred = {};
err = -EOPNOTSUPP;
if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET)
@@ -777,6 +823,9 @@ static int unix_listen(struct socket *sock, int backlog)
err = -EINVAL;
if (!READ_ONCE(u->addr))
goto out; /* No listens on an unbound socket */
+ err = prepare_peercred(&peercred);
+ if (err)
+ goto out;
unix_state_lock(sk);
if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN)
goto out_unlock;
@@ -786,11 +835,12 @@ static int unix_listen(struct socket *sock, int backlog)
WRITE_ONCE(sk->sk_state, TCP_LISTEN);
/* set credentials so connect can copy them */
- update_peercred(sk);
+ update_peercred(sk, &peercred);
err = 0;
out_unlock:
unix_state_unlock(sk);
+ drop_peercred(&peercred);
out:
return err;
}
@@ -1525,6 +1575,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
struct sock *sk = sock->sk, *newsk = NULL, *other = NULL;
struct unix_sock *u = unix_sk(sk), *newu, *otheru;
+ struct af_unix_peercred peercred = {};
struct net *net = sock_net(sk);
struct sk_buff *skb = NULL;
unsigned char state;
@@ -1561,6 +1612,10 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
goto out;
}
+ err = prepare_peercred(&peercred);
+ if (err)
+ goto out;
+
/* Allocate skb for sending to listening sock */
skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL);
if (!skb) {
@@ -1636,7 +1691,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
unix_peer(newsk) = sk;
newsk->sk_state = TCP_ESTABLISHED;
newsk->sk_type = sk->sk_type;
- init_peercred(newsk);
+ init_peercred(newsk, &peercred);
newu = unix_sk(newsk);
newu->listener = other;
RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq);
@@ -1695,20 +1750,33 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
out_free_sk:
unix_release_sock(newsk, 0);
out:
+ drop_peercred(&peercred);
return err;
}
static int unix_socketpair(struct socket *socka, struct socket *sockb)
{
+ struct af_unix_peercred ska_peercred = {}, skb_peercred = {};
struct sock *ska = socka->sk, *skb = sockb->sk;
+ int err;
+
+ err = prepare_peercred(&ska_peercred);
+ if (err)
+ return err;
+
+ err = prepare_peercred(&skb_peercred);
+ if (err) {
+ drop_peercred(&ska_peercred);
+ return err;
+ }
/* Join our sockets back to back */
sock_hold(ska);
sock_hold(skb);
unix_peer(ska) = skb;
unix_peer(skb) = ska;
- init_peercred(ska);
- init_peercred(skb);
+ init_peercred(ska, &ska_peercred);
+ init_peercred(skb, &skb_peercred);
ska->sk_state = TCP_ESTABLISHED;
skb->sk_state = TCP_ESTABLISHED;
--
2.47.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 3/4] pidfs: get rid of __pidfd_prepare()
2025-04-24 12:24 [PATCH RFC 0/4] net, pidfs: enable handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
2025-04-24 12:24 ` [PATCH RFC 1/4] pidfs: register pid in pidfs Christian Brauner
2025-04-24 12:24 ` [PATCH RFC 2/4] net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
@ 2025-04-24 12:24 ` Christian Brauner
2025-04-24 12:24 ` [PATCH RFC 4/4] net, pidfs: enable handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
3 siblings, 0 replies; 13+ messages in thread
From: Christian Brauner @ 2025-04-24 12:24 UTC (permalink / raw)
To: Oleg Nesterov, Kuniyuki Iwashima, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: linux-kernel, linux-fsdevel, netdev, David Rheinsberg, Jan Kara,
Alexander Mikhalitsyn, Luca Boccassi, Lennart Poettering,
Daan De Meyer, Mike Yuan, Christian Brauner
Fold it into pidfd_prepare() and rename PIDFD_CLONE to PIDFD_STALE to
indicate that the passed pid might not have task linkage and no explicit
check for that should be performed.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/pidfs.c | 12 +++----
include/uapi/linux/pidfd.h | 2 +-
kernel/fork.c | 78 ++++++++++++++--------------------------------
3 files changed, 31 insertions(+), 61 deletions(-)
diff --git a/fs/pidfs.c b/fs/pidfs.c
index 8e6c11774c60..3199ec02aaec 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -768,7 +768,7 @@ static inline bool pidfs_pid_valid(struct pid *pid, const struct path *path,
{
enum pid_type type;
- if (flags & PIDFD_CLONE)
+ if (flags & PIDFD_STALE)
return true;
/*
@@ -777,7 +777,7 @@ static inline bool pidfs_pid_valid(struct pid *pid, const struct path *path,
* pidfd has been allocated perform another check that the pid
* is still alive. If it is exit information is available even
* if the task gets reaped before the pidfd is returned to
- * userspace. The only exception is PIDFD_CLONE where no task
+ * userspace. The only exception is PIDFD_STALE where no task
* linkage has been established for @pid yet and the kernel is
* in the middle of process creation so there's nothing for
* pidfs to miss.
@@ -874,11 +874,11 @@ struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags)
int ret;
/*
- * Ensure that PIDFD_CLONE can be passed as a flag without
+ * Ensure that PIDFD_STALE can be passed as a flag without
* overloading other uapi pidfd flags.
*/
- BUILD_BUG_ON(PIDFD_CLONE == PIDFD_THREAD);
- BUILD_BUG_ON(PIDFD_CLONE == PIDFD_NONBLOCK);
+ BUILD_BUG_ON(PIDFD_STALE == PIDFD_THREAD);
+ BUILD_BUG_ON(PIDFD_STALE == PIDFD_NONBLOCK);
ret = path_from_stashed(&pid->stashed, pidfs_mnt, get_pid(pid), &path);
if (ret < 0)
@@ -887,7 +887,7 @@ struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags)
if (!pidfs_pid_valid(pid, &path, flags))
return ERR_PTR(-ESRCH);
- flags &= ~PIDFD_CLONE;
+ flags &= ~PIDFD_STALE;
pidfd_file = dentry_open(&path, flags, current_cred());
/* Raise PIDFD_THREAD explicitly as do_dentry_open() strips it. */
if (!IS_ERR(pidfd_file))
diff --git a/include/uapi/linux/pidfd.h b/include/uapi/linux/pidfd.h
index 2970ef44655a..8c1511edd0e9 100644
--- a/include/uapi/linux/pidfd.h
+++ b/include/uapi/linux/pidfd.h
@@ -12,7 +12,7 @@
#define PIDFD_THREAD O_EXCL
#ifdef __KERNEL__
#include <linux/sched.h>
-#define PIDFD_CLONE CLONE_PIDFD
+#define PIDFD_STALE CLONE_PIDFD
#endif
/* Flags for pidfd_send_signal(). */
diff --git a/kernel/fork.c b/kernel/fork.c
index f7403e1fb0d4..365687e1698f 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2035,50 +2035,6 @@ static inline void rcu_copy_process(struct task_struct *p)
#endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
}
-/**
- * __pidfd_prepare - allocate a new pidfd_file and reserve a pidfd
- * @pid: the struct pid for which to create a pidfd
- * @flags: flags of the new @pidfd
- * @ret: Where to return the file for the pidfd.
- *
- * Allocate a new file that stashes @pid and reserve a new pidfd number in the
- * caller's file descriptor table. The pidfd is reserved but not installed yet.
- *
- * The helper doesn't perform checks on @pid which makes it useful for pidfds
- * created via CLONE_PIDFD where @pid has no task attached when the pidfd and
- * pidfd file are prepared.
- *
- * If this function returns successfully the caller is responsible to either
- * call fd_install() passing the returned pidfd and pidfd file as arguments in
- * order to install the pidfd into its file descriptor table or they must use
- * put_unused_fd() and fput() on the returned pidfd and pidfd file
- * respectively.
- *
- * This function is useful when a pidfd must already be reserved but there
- * might still be points of failure afterwards and the caller wants to ensure
- * that no pidfd is leaked into its file descriptor table.
- *
- * Return: On success, a reserved pidfd is returned from the function and a new
- * pidfd file is returned in the last argument to the function. On
- * error, a negative error code is returned from the function and the
- * last argument remains unchanged.
- */
-static int __pidfd_prepare(struct pid *pid, unsigned int flags, struct file **ret)
-{
- struct file *pidfd_file;
-
- CLASS(get_unused_fd, pidfd)(O_CLOEXEC);
- if (pidfd < 0)
- return pidfd;
-
- pidfd_file = pidfs_alloc_file(pid, flags | O_RDWR);
- if (IS_ERR(pidfd_file))
- return PTR_ERR(pidfd_file);
-
- *ret = pidfd_file;
- return take_fd(pidfd);
-}
-
/**
* pidfd_prepare - allocate a new pidfd_file and reserve a pidfd
* @pid: the struct pid for which to create a pidfd
@@ -2108,14 +2064,19 @@ 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)
{
- /*
- * While holding the pidfd waitqueue lock removing the task
- * linkage for the thread-group leader pid (PIDTYPE_TGID) isn't
- * possible. Thus, if there's still task linkage for PIDTYPE_PID
- * not having thread-group leader linkage for the pid means it
- * wasn't a thread-group leader in the first place.
- */
- scoped_guard(spinlock_irq, &pid->wait_pidfd.lock) {
+ struct file *pidfd_file;
+
+ if (!(flags & PIDFD_STALE)) {
+ /*
+ * While holding the pidfd waitqueue lock removing the
+ * task linkage for the thread-group leader pid
+ * (PIDTYPE_TGID) isn't possible. Thus, if there's still
+ * task linkage for PIDTYPE_PID not having thread-group
+ * leader linkage for the pid means it wasn't a
+ * thread-group leader in the first place.
+ */
+ guard(spinlock_irq)(&pid->wait_pidfd.lock);
+
/* Task has already been reaped. */
if (!pid_has_task(pid, PIDTYPE_PID))
return -ESRCH;
@@ -2128,7 +2089,16 @@ int pidfd_prepare(struct pid *pid, unsigned int flags, struct file **ret)
return -ENOENT;
}
- return __pidfd_prepare(pid, flags, ret);
+ CLASS(get_unused_fd, pidfd)(O_CLOEXEC);
+ if (pidfd < 0)
+ return pidfd;
+
+ pidfd_file = pidfs_alloc_file(pid, flags | O_RDWR);
+ if (IS_ERR(pidfd_file))
+ return PTR_ERR(pidfd_file);
+
+ *ret = pidfd_file;
+ return take_fd(pidfd);
}
static void __delayed_free_task(struct rcu_head *rhp)
@@ -2477,7 +2447,7 @@ __latent_entropy struct task_struct *copy_process(
* Note that no task has been attached to @pid yet indicate
* that via CLONE_PIDFD.
*/
- retval = __pidfd_prepare(pid, flags | PIDFD_CLONE, &pidfile);
+ retval = pidfd_prepare(pid, flags | PIDFD_STALE, &pidfile);
if (retval < 0)
goto bad_fork_free_pid;
pidfd = retval;
--
2.47.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH RFC 4/4] net, pidfs: enable handing out pidfds for reaped sk->sk_peer_pid
2025-04-24 12:24 [PATCH RFC 0/4] net, pidfs: enable handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
` (2 preceding siblings ...)
2025-04-24 12:24 ` [PATCH RFC 3/4] pidfs: get rid of __pidfd_prepare() Christian Brauner
@ 2025-04-24 12:24 ` Christian Brauner
3 siblings, 0 replies; 13+ messages in thread
From: Christian Brauner @ 2025-04-24 12:24 UTC (permalink / raw)
To: Oleg Nesterov, Kuniyuki Iwashima, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: linux-kernel, linux-fsdevel, netdev, David Rheinsberg, Jan Kara,
Alexander Mikhalitsyn, Luca Boccassi, Lennart Poettering,
Daan De Meyer, Mike Yuan, Christian Brauner
Now that all preconditions are met, allow handing out pidfs for reaped
sk->sk_peer_pids.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
net/core/sock.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/core/sock.c b/net/core/sock.c
index b969d2210656..017b02b69e8b 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -148,6 +148,8 @@
#include <linux/ethtool.h>
+#include <uapi/linux/pidfd.h>
+
#include "dev.h"
static DEFINE_MUTEX(proto_list_mutex);
@@ -1891,7 +1893,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
if (!peer_pid)
return -ENODATA;
- pidfd = pidfd_prepare(peer_pid, 0, &pidfd_file);
+ pidfd = pidfd_prepare(peer_pid, PIDFD_STALE, &pidfd_file);
put_pid(peer_pid);
if (pidfd < 0) {
/*
--
2.47.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH RFC 2/4] net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid
2025-04-24 12:24 ` [PATCH RFC 2/4] net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
@ 2025-04-24 12:44 ` David Rheinsberg
2025-04-24 15:19 ` Christian Brauner
2025-04-25 1:57 ` Kuniyuki Iwashima
1 sibling, 1 reply; 13+ messages in thread
From: David Rheinsberg @ 2025-04-24 12:44 UTC (permalink / raw)
To: Christian Brauner, Oleg Nesterov, Kuniyuki Iwashima,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman
Cc: linux-kernel, linux-fsdevel, netdev, Jan Kara,
Alexander Mikhalitsyn, Luca Boccassi, Lennart Poettering,
Daan De Meyer, Mike Yuan
Hi
On Thu, Apr 24, 2025, at 2:24 PM, Christian Brauner wrote:
[...]
> Link:
> https://lore.kernel.org/lkml/20230807085203.819772-1-david@readahead.eu
> [1]
> Signed-off-by: Christian Brauner <brauner@kernel.org>
Very nice! Highly appreciated!
> ---
> net/unix/af_unix.c | 90
> +++++++++++++++++++++++++++++++++++++++++++++++-------
> 1 file changed, 79 insertions(+), 11 deletions(-)
>
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index f78a2492826f..83b5aebf499e 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -100,6 +100,7 @@
> #include <linux/splice.h>
> #include <linux/string.h>
> #include <linux/uaccess.h>
> +#include <linux/pidfs.h>
> #include <net/af_unix.h>
> #include <net/net_namespace.h>
> #include <net/scm.h>
> @@ -643,6 +644,14 @@ static void unix_sock_destructor(struct sock *sk)
> return;
> }
>
> + if (sock_flag(sk, SOCK_RCU_FREE)) {
> + pr_info("Attempting to release RCU protected socket with sleeping
> locks: %p\n", sk);
> + return;
> + }
unix-sockets do not use `SOCK_RCU_FREE`, but even if they did, doesn't this flag imply that the destructor is delayed via `call_rcu`, and thus *IS* allowed to sleep? And then, sleeping in the destructor is always safe, isn't it? `SOCK_RCU_FREE` just guarantees that it is delayed for at least an RCU grace period, right? Not sure, what you are getting at here, but I might be missing something obvious as well.
Regardless, wouldn't you want WARN_ON_ONCE() rather than pr_info?
Otherwise looks good to me!
David
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH RFC 1/4] pidfs: register pid in pidfs
2025-04-24 12:24 ` [PATCH RFC 1/4] pidfs: register pid in pidfs Christian Brauner
@ 2025-04-24 13:24 ` Oleg Nesterov
2025-04-24 15:19 ` Christian Brauner
0 siblings, 1 reply; 13+ messages in thread
From: Oleg Nesterov @ 2025-04-24 13:24 UTC (permalink / raw)
To: Christian Brauner
Cc: Kuniyuki Iwashima, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, linux-kernel, linux-fsdevel, netdev,
David Rheinsberg, Jan Kara, Alexander Mikhalitsyn, Luca Boccassi,
Lennart Poettering, Daan De Meyer, Mike Yuan
On 04/24, Christian Brauner wrote:
>
> + * pidfs_register_pid - pin a struct pid through pidfs
> + * @pid: pid to pin
> + *
> + * Pin a struct pid through pidfs. Needs to be paired with
> + * pidfds_put_put() to not risk leaking the pidfs dentry and inode.
^^^^^^^^^^^^^^
pidfs_put_pid ;)
Can't review 2/4, for other patches in series
Reviewed-by: Oleg Nesterov <oleg@redhat.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH RFC 2/4] net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid
2025-04-24 12:44 ` David Rheinsberg
@ 2025-04-24 15:19 ` Christian Brauner
2025-04-25 1:08 ` Kuniyuki Iwashima
0 siblings, 1 reply; 13+ messages in thread
From: Christian Brauner @ 2025-04-24 15:19 UTC (permalink / raw)
To: David Rheinsberg
Cc: Oleg Nesterov, Kuniyuki Iwashima, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, linux-kernel,
linux-fsdevel, netdev, Jan Kara, Alexander Mikhalitsyn,
Luca Boccassi, Lennart Poettering, Daan De Meyer, Mike Yuan
On Thu, Apr 24, 2025 at 02:44:13PM +0200, David Rheinsberg wrote:
> Hi
>
> On Thu, Apr 24, 2025, at 2:24 PM, Christian Brauner wrote:
> [...]
> > Link:
> > https://lore.kernel.org/lkml/20230807085203.819772-1-david@readahead.eu
> > [1]
> > Signed-off-by: Christian Brauner <brauner@kernel.org>
>
> Very nice! Highly appreciated!
>
> > ---
> > net/unix/af_unix.c | 90
> > +++++++++++++++++++++++++++++++++++++++++++++++-------
> > 1 file changed, 79 insertions(+), 11 deletions(-)
> >
> > diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> > index f78a2492826f..83b5aebf499e 100644
> > --- a/net/unix/af_unix.c
> > +++ b/net/unix/af_unix.c
> > @@ -100,6 +100,7 @@
> > #include <linux/splice.h>
> > #include <linux/string.h>
> > #include <linux/uaccess.h>
> > +#include <linux/pidfs.h>
> > #include <net/af_unix.h>
> > #include <net/net_namespace.h>
> > #include <net/scm.h>
> > @@ -643,6 +644,14 @@ static void unix_sock_destructor(struct sock *sk)
> > return;
> > }
> >
> > + if (sock_flag(sk, SOCK_RCU_FREE)) {
> > + pr_info("Attempting to release RCU protected socket with sleeping
> > locks: %p\n", sk);
> > + return;
> > + }
>
> unix-sockets do not use `SOCK_RCU_FREE`, but even if they did, doesn't
> this flag imply that the destructor is delayed via `call_rcu`, and
> thus *IS* allowed to sleep? And then, sleeping in the destructor is
> always safe, isn't it? `SOCK_RCU_FREE` just guarantees that it is
> delayed for at least an RCU grace period, right? Not sure, what you
> are getting at here, but I might be missing something obvious as well.
Callbacks run from call_rcu() can be called from softirq context and in
general are not allowed to block. That's what queue_rcu_work() is for
which uses system_unbound_wq.
>
> Regardless, wouldn't you want WARN_ON_ONCE() rather than pr_info?
Sure.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH RFC 1/4] pidfs: register pid in pidfs
2025-04-24 13:24 ` Oleg Nesterov
@ 2025-04-24 15:19 ` Christian Brauner
0 siblings, 0 replies; 13+ messages in thread
From: Christian Brauner @ 2025-04-24 15:19 UTC (permalink / raw)
To: Oleg Nesterov
Cc: Kuniyuki Iwashima, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, linux-kernel, linux-fsdevel, netdev,
David Rheinsberg, Jan Kara, Alexander Mikhalitsyn, Luca Boccassi,
Lennart Poettering, Daan De Meyer, Mike Yuan
On Thu, Apr 24, 2025 at 03:24:38PM +0200, Oleg Nesterov wrote:
> On 04/24, Christian Brauner wrote:
> >
> > + * pidfs_register_pid - pin a struct pid through pidfs
> > + * @pid: pid to pin
> > + *
> > + * Pin a struct pid through pidfs. Needs to be paired with
> > + * pidfds_put_put() to not risk leaking the pidfs dentry and inode.
> ^^^^^^^^^^^^^^
>
> pidfs_put_pid ;)
Dammmit, thanks!
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH RFC 2/4] net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid
2025-04-24 15:19 ` Christian Brauner
@ 2025-04-25 1:08 ` Kuniyuki Iwashima
2025-04-25 8:02 ` Christian Brauner
0 siblings, 1 reply; 13+ messages in thread
From: Kuniyuki Iwashima @ 2025-04-25 1:08 UTC (permalink / raw)
To: brauner
Cc: alexander, bluca, daan.j.demeyer, davem, david, edumazet, horms,
jack, kuba, kuniyu, lennart, linux-fsdevel, linux-kernel, me,
netdev, oleg, pabeni
From: Christian Brauner <brauner@kernel.org>
Date: Thu, 24 Apr 2025 17:19:28 +0200
> > > @@ -643,6 +644,14 @@ static void unix_sock_destructor(struct sock *sk)
> > > return;
> > > }
> > >
> > > + if (sock_flag(sk, SOCK_RCU_FREE)) {
> > > + pr_info("Attempting to release RCU protected socket with sleeping
> > > locks: %p\n", sk);
> > > + return;
> > > + }
> >
> > unix-sockets do not use `SOCK_RCU_FREE`,
Right, and I think we won't flag SOCK_RCU_FREE in the future.
> but even if they did, doesn't
> > this flag imply that the destructor is delayed via `call_rcu`, and
> > thus *IS* allowed to sleep? And then, sleeping in the destructor is
> > always safe, isn't it? `SOCK_RCU_FREE` just guarantees that it is
> > delayed for at least an RCU grace period, right? Not sure, what you
> > are getting at here, but I might be missing something obvious as well.
>
> Callbacks run from call_rcu() can be called from softirq context and in
> general are not allowed to block. That's what queue_rcu_work() is for
> which uses system_unbound_wq.
>
> >
> > Regardless, wouldn't you want WARN_ON_ONCE() rather than pr_info?
>
> Sure.
I prefer DEBUG_NET_WARN_ON_ONCE() or removing it as rcu_sleep_check()
in __might_sleep() has better checks.
The netdev CI enables debug.config, which has CONFIG_DEBUG_ATOMIC_SLEEP
and enables the checks, so adding a test case in
tools/testing/selftests/net/af_unix/scm_pidfd.c will catch the future
regression.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH RFC 2/4] net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid
2025-04-24 12:24 ` [PATCH RFC 2/4] net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
2025-04-24 12:44 ` David Rheinsberg
@ 2025-04-25 1:57 ` Kuniyuki Iwashima
2025-04-25 7:58 ` Christian Brauner
1 sibling, 1 reply; 13+ messages in thread
From: Kuniyuki Iwashima @ 2025-04-25 1:57 UTC (permalink / raw)
To: brauner
Cc: alexander, bluca, daan.j.demeyer, davem, david, edumazet, horms,
jack, kuba, kuniyu, lennart, linux-fsdevel, linux-kernel, me,
netdev, oleg, pabeni
From: Christian Brauner <brauner@kernel.org>
Date: Thu, 24 Apr 2025 14:24:35 +0200
> @@ -734,13 +743,48 @@ static void unix_release_sock(struct sock *sk, int embrion)
> unix_gc(); /* Garbage collect fds */
> }
>
> -static void init_peercred(struct sock *sk)
> +struct af_unix_peercred {
nit: conventional naming for AF_UNIX is without af_, all structs
(and most functions) start with unix_.
> + struct pid *peer_pid;
> + const struct cred *peer_cred;
> +};
> +
> +static inline int prepare_peercred(struct af_unix_peercred *peercred)
> +{
> + struct pid *pid;
> + int err;
> +
> + pid = task_tgid(current);
> + err = pidfs_register_pid(pid);
> + if (likely(!err)) {
> + peercred->peer_pid = get_pid(pid);
> + peercred->peer_cred = get_current_cred();
> + }
> + return err;
> +}
> +
> +static void drop_peercred(struct af_unix_peercred *peercred)
> +{
> + struct pid *pid = NULL;
> + const struct cred *cred = NULL;
another nit: please keep variables in reverse xmas tree order.
https://docs.kernel.org/process/maintainer-netdev.html#local-variable-ordering-reverse-xmas-tree-rcs
Otherwise looks good to me.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH RFC 2/4] net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid
2025-04-25 1:57 ` Kuniyuki Iwashima
@ 2025-04-25 7:58 ` Christian Brauner
0 siblings, 0 replies; 13+ messages in thread
From: Christian Brauner @ 2025-04-25 7:58 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: alexander, bluca, daan.j.demeyer, davem, david, edumazet, horms,
jack, kuba, lennart, linux-fsdevel, linux-kernel, me, netdev,
oleg, pabeni
On Thu, Apr 24, 2025 at 06:57:19PM -0700, Kuniyuki Iwashima wrote:
> From: Christian Brauner <brauner@kernel.org>
> Date: Thu, 24 Apr 2025 14:24:35 +0200
> > @@ -734,13 +743,48 @@ static void unix_release_sock(struct sock *sk, int embrion)
> > unix_gc(); /* Garbage collect fds */
> > }
> >
> > -static void init_peercred(struct sock *sk)
> > +struct af_unix_peercred {
>
> nit: conventional naming for AF_UNIX is without af_, all structs
> (and most functions) start with unix_.
Done.
>
>
> > + struct pid *peer_pid;
> > + const struct cred *peer_cred;
> > +};
> > +
> > +static inline int prepare_peercred(struct af_unix_peercred *peercred)
> > +{
> > + struct pid *pid;
> > + int err;
> > +
> > + pid = task_tgid(current);
> > + err = pidfs_register_pid(pid);
> > + if (likely(!err)) {
> > + peercred->peer_pid = get_pid(pid);
> > + peercred->peer_cred = get_current_cred();
> > + }
> > + return err;
> > +}
> > +
> > +static void drop_peercred(struct af_unix_peercred *peercred)
> > +{
> > + struct pid *pid = NULL;
> > + const struct cred *cred = NULL;
>
> another nit: please keep variables in reverse xmas tree order.
> https://docs.kernel.org/process/maintainer-netdev.html#local-variable-ordering-reverse-xmas-tree-rcs
Done.
>
> Otherwise looks good to me.
Thanks!
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH RFC 2/4] net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid
2025-04-25 1:08 ` Kuniyuki Iwashima
@ 2025-04-25 8:02 ` Christian Brauner
0 siblings, 0 replies; 13+ messages in thread
From: Christian Brauner @ 2025-04-25 8:02 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: alexander, bluca, daan.j.demeyer, davem, david, edumazet, horms,
jack, kuba, lennart, linux-fsdevel, linux-kernel, me, netdev,
oleg, pabeni
> I prefer DEBUG_NET_WARN_ON_ONCE() or removing it as rcu_sleep_check()
I've removed it.
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2025-04-25 8:02 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-24 12:24 [PATCH RFC 0/4] net, pidfs: enable handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
2025-04-24 12:24 ` [PATCH RFC 1/4] pidfs: register pid in pidfs Christian Brauner
2025-04-24 13:24 ` Oleg Nesterov
2025-04-24 15:19 ` Christian Brauner
2025-04-24 12:24 ` [PATCH RFC 2/4] net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
2025-04-24 12:44 ` David Rheinsberg
2025-04-24 15:19 ` Christian Brauner
2025-04-25 1:08 ` Kuniyuki Iwashima
2025-04-25 8:02 ` Christian Brauner
2025-04-25 1:57 ` Kuniyuki Iwashima
2025-04-25 7:58 ` Christian Brauner
2025-04-24 12:24 ` [PATCH RFC 3/4] pidfs: get rid of __pidfd_prepare() Christian Brauner
2025-04-24 12:24 ` [PATCH RFC 4/4] net, pidfs: enable handing out pidfds for reaped sk->sk_peer_pid Christian Brauner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).