Add SCM_PIDFD and SO_PEERPIDFD
Subsystems (12)
v7 cover Add SCM_PIDFD and SO_PEERPIDFD
1. Implement SCM_PIDFD, a new type of CMSG type analogical to SCM_CREDENTIALS, but it contains pidfd instead of plain pid, which allows programmers not to care about PID reuse problem.
2. Add SO_PEERPIDFD which allows to get pidfd of peer socket holder pidfd. This thing is direct analog of SO_PEERCRED which allows to get plain PID.
3. Add SCM_PIDFD / SO_PEERPIDFD kselftest
Idea comes from UAPI kernel group:
https://uapi-group.org/kernel-features/
Big thanks to Christian Brauner and Lennart Poettering for productive discussions about this and Luca Boccassi for testing and reviewing this.
=== Motivation behind this patchset
Eric Dumazet raised a question:
Quoted 2 lines
It seems that we already can use
pidfd_open()(since linux-5.3), and pass the resulting fd inaf_unixSCM_RIGHTSmessage ?
Yes, it's possible, but it means that from the receiver side we need to trust the sent pidfd (in SCM_RIGHTS),
or always use combination of SCM_RIGHTS+SCM_CREDENTIALS, then we can extract pidfd from SCM_RIGHTS,
then acquire plain pid from pidfd and after compare it with the pid from SCM_CREDENTIALS.
A few comments from other folks regarding this.
Quoted 25 lines · Christian Brauner
Let me try and provide some of the missing background.
There are a range of use-cases where we would like to authenticate a client through sockets without being susceptible to PID recycling attacks. Currently, we can't do this as the race isn't fully fixable. We can only apply mitigations.
What this patchset will allows us to do is to get a pidfd without the client having to send us an fd explicitly via
SCM_RIGHTS. As that's already possibly as you correctly point out.But for protocols like polkit this is quite important. Every message is standalone and we would need to force a complete protocol change where we would need to require that every client allocate and send a pidfd via
SCM_RIGHTS. That would also mean patching through all polkit users.For something like systemd-journald where we provide logging facilities and want to add metadata to the log we would also immensely benefit from being able to get a receiver-side controlled pidfd.
With the message type we envisioned we don't need to change the sender at all and can be safe against pid recycling.
Quoted 28 lines · Lennart Poettering
So yes, this is of course possible, but it would mean the pidfd would have to be transported as part of the user protocol, explicitly sent by the sender. (Moreover, the receiver after receiving the pidfd would then still have to somehow be able to prove that the pidfd it just received actually refers to the peer's process and not some random process. – this part is actually solvable in userspace, but ugly)
The big thing is simply that we want that the pidfd is associated *implicity* with each
AF_UNIXconnection, not explicitly. A lot of userspace already relies on this, both in the authentication area (polkit) as well as in the logging area (systemd-journald). Right now using the PID field from SO_PEERCREDS/SCM_CREDENTIALS is racy though and very hard to get right. Making this available as pidfd too, would solve this raciness, without otherwise changing semantics of it all:
receivers can still enable the creds stuff as they wish, and the data is then implicitly appended to the connections/datagrams the sender initiates.Or to turn this around: things like polkit are typically used to authenticate arbitrary dbus methods calls: some service implements a dbus method call, and when an unprivileged client then issues that call, it will take the client's info, go to polkit and ask it if this is ok. If we wanted to send the pidfd as part of the protocol we basically would have to extend every single method call to contain the client's pidfd along with it as an additional argument, which would be a massive undertaking: it would change the prototypes of basically *all* methods a service defines… And that's just ugly.
Quoted 6 lines
Note that Alex' patch set doesn't expose anything that wasn't exposed before, or attach, propagate what wasn't before. All it does, is make the field already available anyway (the struct ucred .pid field) available also in a better way (as a pidfd), to solve a variety of races, with no effect on the protocol actually spoken within the
AF_UNIXtransport. It's a seamless improvement of the status quo.
===
Git tree:
https://github.com/mihalicyn/linux/tree/scm_pidfd
Alexander Mikhalitsyn (4):
scm: add SO_PASSPIDFD and SCM_PIDFD
net: core: add getsockopt SO_PEERPIDFD
selftests: net: add SCM_PIDFD / SO_PEERPIDFD test
af_unix: Kconfig: make CONFIG_UNIX bool
arch/alpha/include/uapi/asm/socket.h | 3 + arch/mips/include/uapi/asm/socket.h | 3 + arch/parisc/include/uapi/asm/socket.h | 3 + arch/sparc/include/uapi/asm/socket.h | 3 + include/linux/net.h | 1 + include/linux/socket.h | 1 + include/net/scm.h | 39 +- include/uapi/asm-generic/socket.h | 3 + net/core/sock.c | 44 ++ net/mptcp/sockopt.c | 1 + net/unix/Kconfig | 6 +- net/unix/af_unix.c | 34 +- tools/include/uapi/asm-generic/socket.h | 3 + tools/testing/selftests/net/.gitignore | 1 + tools/testing/selftests/net/af_unix/Makefile | 3 +- .../testing/selftests/net/af_unix/scm_pidfd.c | 430 ++++++++++++++++++ 16 files changed, 565 insertions(+), 13 deletions(-) create mode 100644 tools/testing/selftests/net/af_unix/scm_pidfd.c
Signature · 1 line
2.34.1
PATCH v7 1/4 scm: add SO_PASSPIDFD and SCM_PIDFD
Implement SCM_PIDFD, a new type of CMSG type analogical to SCM_CREDENTIALS, but it contains pidfd instead of plain pid, which allows programmers not to care about PID reuse problem.
We mask SO_PASSPIDFD feature if CONFIG_UNIX is not builtin because it depends on a pidfd_prepare() API which is not exported to the kernel modules.
Idea comes from UAPI kernel group:
https://uapi-group.org/kernel-features/
Big thanks to Christian Brauner and Lennart Poettering for productive discussions about this.
---
v7:
- removed CONFIG_UNIX checks, because we've converted CONFIG_UNIX to be boolean
v6:
- disable feature when CONFIG_UNIX=n/m (pidfd_prepare API is not exported to modules)
v5:
- no changes
v4:
- fixed silent fd_install if writting of CMSG to the userspace fails (pointed by Christian)
v2:
According to review comments from Kuniyuki Iwashima and Christian Brauner:
- use pidfd_create(..) retval as a result
- whitespace change
--- arch/alpha/include/uapi/asm/socket.h | 2 ++ arch/mips/include/uapi/asm/socket.h | 2 ++ arch/parisc/include/uapi/asm/socket.h | 2 ++ arch/sparc/include/uapi/asm/socket.h | 2 ++ include/linux/net.h | 1 + include/linux/socket.h | 1 + include/net/scm.h | 39 +++++++++++++++++++++++-- include/uapi/asm-generic/socket.h | 2 ++ net/core/sock.c | 11 +++++++ net/mptcp/sockopt.c | 1 + net/unix/af_unix.c | 18 ++++++++---- tools/include/uapi/asm-generic/socket.h | 2 ++ 12 files changed, 76 insertions(+), 7 deletions(-)
arch/alpha/include/uapi/asm/socket.h +2 -0
@@ -137,6 +137,8 @@#define SO_RCVMARK 75 +#define SO_PASSPIDFD 76 +#if !defined(__KERNEL__)#if __BITS_PER_LONG ==64
arch/mips/include/uapi/asm/socket.h +2 -0
@@ -148,6 +148,8 @@#define SO_RCVMARK 75 +#define SO_PASSPIDFD 76 +#if !defined(__KERNEL__)#if __BITS_PER_LONG ==64
arch/parisc/include/uapi/asm/socket.h +2 -0
@@ -129,6 +129,8 @@#define SO_RCVMARK 0x4049 +#define SO_PASSPIDFD 0x404A +#if !defined(__KERNEL__)#if __BITS_PER_LONG ==64
arch/sparc/include/uapi/asm/socket.h +2 -0
@@ -130,6 +130,8 @@#define SO_RCVMARK 0x0054 +#define SO_PASSPIDFD 0x0055 +#if !defined(__KERNEL__)
include/linux/net.h +1 -0
@@ -43,6 +43,7 @@ struct net;#define SOCK_PASSSEC 4#define SOCK_SUPPORT_ZC 5#define SOCK_CUSTOM_SOCKOPT 6 +#define SOCK_PASSPIDFD 7#ifndef ARCH_HAS_SOCKET_TYPES /**
include/linux/socket.h +1 -0
@@ -177,6 +177,7 @@ static inline size_t msg_data_left(struct msghdr *msg)#define SCM_RIGHTS 0x01/* rw: access rights (array of int) */ #define SCM_CREDENTIALS 0x02/* rw: struct ucred */ #define SCM_SECURITY 0x03/* rw: security label */ +#define SCM_PIDFD 0x04/* ro: pidfd (int) */ struct ucred {__u32 pid;
include/net/scm.h +37 -2
@@ -120,12 +120,44 @@ static inline bool scm_has_secdata(struct socket *sock) }#endif /* CONFIG_SECURITY_NETWORK */ +static __inline__void scm_pidfd_recv (struct msghdr *msg,struct scm_cookie *scm) +{ +struct file *pidfd_file =NULL ; +int pidfd; + +/* +* put_cmsg() doesn't return an error if CMSG is truncated, +* that's why we need to opencode these checks here. +*/ +if ((msg->msg_controllen <=sizeof (struct cmsghdr )) || + (msg->msg_controllen -sizeof (struct cmsghdr )) <sizeof (int )) { + msg->msg_flags |=MSG_CTRUNC ; +return ; + } + +WARN_ON_ONCE (!scm->pid); + pidfd =pidfd_prepare (scm->pid,0 , &pidfd_file); + +if (put_cmsg (msg,SOL_SOCKET ,SCM_PIDFD ,sizeof (int ), &pidfd)) { +if (pidfd_file) { +put_unused_fd (pidfd); +fput (pidfd_file); + } + +return ; + } + +if (pidfd_file) +fd_install (pidfd, pidfd_file); +} +static __inline__void scm_recv (struct socket *sock,struct msghdr *msg,struct scm_cookie *scm,int flags) {if (!msg->msg_control) { -if (test_bit (SOCK_PASSCRED , &sock->flags) || scm->fp || -scm_has_secdata (sock)) +if (test_bit (SOCK_PASSCRED , &sock->flags) || +test_bit (SOCK_PASSPIDFD , &sock->flags) || + scm->fp ||scm_has_secdata (sock)) msg->msg_flags |=MSG_CTRUNC ;scm_destroy (scm);return ;
@@ -141,6 +173,9 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,put_cmsg (msg,SOL_SOCKET ,SCM_CREDENTIALS ,sizeof (ucreds), &ucreds); } +if (test_bit (SOCK_PASSPIDFD , &sock->flags)) +scm_pidfd_recv (msg, scm); +scm_destroy_cred (scm);scm_passec (sock, msg, scm);
include/uapi/asm-generic/socket.h +2 -0
@@ -132,6 +132,8 @@#define SO_RCVMARK 75 +#define SO_PASSPIDFD 76 +#if !defined(__KERNEL__)#if __BITS_PER_LONG ==64 || (defined(__x86_64__) && defined(__ILP32__))
net/core/sock.c +11 -0
@@ -1246,6 +1246,13 @@ int sk_setsockopt(struct sock *sk, int level, int optname,clear_bit (SOCK_PASSCRED , &sock->flags);break ; +case SO_PASSPIDFD : +if (valbool) +set_bit (SOCK_PASSPIDFD , &sock->flags); +else +clear_bit (SOCK_PASSPIDFD , &sock->flags); +break ; +case SO_TIMESTAMP_OLD :case SO_TIMESTAMP_NEW :case SO_TIMESTAMPNS_OLD :
@@ -1732,6 +1739,10 @@ int sk_getsockopt(struct sock *sk, int level, int optname, v.val = !!test_bit (SOCK_PASSCRED , &sock->flags);break ; +case SO_PASSPIDFD : + v.val = !!test_bit (SOCK_PASSPIDFD , &sock->flags); +break ; +case SO_PEERCRED : {struct ucred peercred;
net/mptcp/sockopt.c +1 -0
@@ -355,6 +355,7 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname,case SO_BROADCAST :case SO_BSDCOMPAT :case SO_PASSCRED : +case SO_PASSPIDFD :case SO_PASSSEC :case SO_RXQ_OVFL :case SO_WIFI_STATUS :
net/unix/af_unix.c +13 -5
@@ -1361,7 +1361,8 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,if (err) goto out; -if (test_bit (SOCK_PASSCRED , &sock->flags) && +if ((test_bit (SOCK_PASSCRED , &sock->flags) || +test_bit (SOCK_PASSPIDFD , &sock->flags)) && !unix_sk (sk)->addr) { err =unix_autobind (sk);if (err)
@@ -1469,7 +1470,8 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,if (err) goto out; -if (test_bit (SOCK_PASSCRED , &sock->flags) && !u->addr) { +if ((test_bit (SOCK_PASSCRED , &sock->flags) || +test_bit (SOCK_PASSPIDFD , &sock->flags)) && !u->addr) { err =unix_autobind (sk);if (err) goto out;
@@ -1670,6 +1672,8 @@ static void unix_sock_inherit_flags(const struct socket *old, {if (test_bit (SOCK_PASSCRED , &old->flags))set_bit (SOCK_PASSCRED , &new->flags); +if (test_bit (SOCK_PASSPIDFD , &old->flags)) +set_bit (SOCK_PASSPIDFD , &new->flags);if (test_bit (SOCK_PASSSEC , &old->flags))set_bit (SOCK_PASSSEC , &new->flags); }
@@ -1819,8 +1823,10 @@ static bool unix_passcred_enabled(const struct socket *sock, const struct sock *other) {return test_bit (SOCK_PASSCRED , &sock->flags) || +test_bit (SOCK_PASSPIDFD , &sock->flags) || !other->sk_socket || -test_bit (SOCK_PASSCRED , &other->sk_socket->flags); +test_bit (SOCK_PASSCRED , &other->sk_socket->flags) || +test_bit (SOCK_PASSPIDFD , &other->sk_socket->flags); }/*
@@ -1904,7 +1910,8 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, goto out; } -if (test_bit (SOCK_PASSCRED , &sock->flags) && !u->addr) { +if ((test_bit (SOCK_PASSCRED , &sock->flags) || +test_bit (SOCK_PASSPIDFD , &sock->flags)) && !u->addr) { err =unix_autobind (sk);if (err) goto out;
@@ -2718,7 +2725,8 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state,/* Never glue messages from different writers */ if (!unix_skb_scm_eq (skb, &scm))break ; - }else if (test_bit (SOCK_PASSCRED , &sock->flags)) { + }else if (test_bit (SOCK_PASSCRED , &sock->flags) || +test_bit (SOCK_PASSPIDFD , &sock->flags)) {/* Copy credentials */ scm_set_cred (&scm,UNIXCB (skb).pid,UNIXCB (skb).uid,UNIXCB (skb).gid);unix_set_secdata (&scm, skb);
tools/include/uapi/asm-generic/socket.h +2 -0
@@ -121,6 +121,8 @@#define SO_RCVMARK 75 +#define SO_PASSPIDFD 76 +#if !defined(__KERNEL__)#if __BITS_PER_LONG ==64 || (defined(__x86_64__) && defined(__ILP32__))
Signature · 1 line
2.34.1
Re: [PATCH net-next v7 1/4] scm: add SO_PASSPIDFD and SCM_PIDFD
Quoted 34 lines · Alexander Mikhalitsyn
Implement
SCM_PIDFD, a new type of CMSG type analogical toSCM_CREDENTIALS, but it contains pidfd instead of plain pid, which allows programmers not to care about PID reuse problem.We mask
SO_PASSPIDFDfeature ifCONFIG_UNIXis not builtin because it depends on apidfd_prepare()API which is not exported to the kernel modules.Idea comes from UAPI kernel group:
https://uapi-group.org/kernel-features/Big thanks to Christian Brauner and Lennart Poettering for productive discussions about this.
Cc "David S. Miller" <[email protected]>Cc Eric Dumazet <[email protected]>Cc Jakub Kicinski <[email protected]>Cc Paolo Abeni <[email protected]>Cc Leon Romanovsky <[email protected]>Cc David Ahern <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Kees Cook <[email protected]>Cc Christian Brauner <[email protected]>Cc Kuniyuki Iwashima <[email protected]>Cc Lennart Poettering <[email protected]>Cc Luca Boccassi <[email protected]>Tested-by Luca Boccassi <[email protected]>Reviewed-by Kuniyuki Iwashima <[email protected]>Reviewed-by Christian Brauner <[email protected]>Signed-off-by Alexander Mikhalitsyn <[email protected]>
Quoted 1 line
---
Re: [PATCH net-next v7 1/4] scm: add SO_PASSPIDFD and SCM_PIDFD
Quoted 39 lines · Eric Dumazet
Quoted 34 lines · Alexander Mikhalitsyn
Implement
SCM_PIDFD, a new type of CMSG type analogical toSCM_CREDENTIALS, but it contains pidfd instead of plain pid, which allows programmers not to care about PID reuse problem.We mask
SO_PASSPIDFDfeature ifCONFIG_UNIXis not builtin because it depends on apidfd_prepare()API which is not exported to the kernel modules.Idea comes from UAPI kernel group:
https://uapi-group.org/kernel-features/Big thanks to Christian Brauner and Lennart Poettering for productive discussions about this.
Cc "David S. Miller" <[email protected]>Cc Eric Dumazet <[email protected]>Cc Jakub Kicinski <[email protected]>Cc Paolo Abeni <[email protected]>Cc Leon Romanovsky <[email protected]>Cc David Ahern <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Kees Cook <[email protected]>Cc Christian Brauner <[email protected]>Cc Kuniyuki Iwashima <[email protected]>Cc Lennart Poettering <[email protected]>Cc Luca Boccassi <[email protected]>Tested-by Luca Boccassi <[email protected]>Reviewed-by Kuniyuki Iwashima <[email protected]>Reviewed-by Christian Brauner <[email protected]>Signed-off-by Alexander Mikhalitsyn <[email protected]>Quoted 1 line
---
Quoted 1 line
Reviewed-by Eric Dumazet <[email protected]>
Thanks, Eric!
Kind regards,
Alex
Re: [PATCH net-next v7 1/4] scm: add SO_PASSPIDFD and SCM_PIDFD
In reply to Alexander MikhalitsynQuoted 47 lines · Alexander Mikhalitsyn
Implement
SCM_PIDFD, a new type of CMSG type analogical toSCM_CREDENTIALS, but it contains pidfd instead of plain pid, which allows programmers not to care about PID reuse problem.We mask
SO_PASSPIDFDfeature ifCONFIG_UNIXis not builtin because it depends on apidfd_prepare()API which is not exported to the kernel modules.Idea comes from UAPI kernel group:
https://uapi-group.org/kernel-features/Big thanks to Christian Brauner and Lennart Poettering for productive discussions about this.
Cc "David S. Miller" <[email protected]>Cc Eric Dumazet <[email protected]>Cc Jakub Kicinski <[email protected]>Cc Paolo Abeni <[email protected]>Cc Leon Romanovsky <[email protected]>Cc David Ahern <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Kees Cook <[email protected]>Cc Christian Brauner <[email protected]>Cc Kuniyuki Iwashima <[email protected]>Cc Lennart Poettering <[email protected]>Cc Luca Boccassi <[email protected]>Tested-by Luca Boccassi <[email protected]>Reviewed-by Kuniyuki Iwashima <[email protected]>Reviewed-by Christian Brauner <[email protected]>Signed-off-by Alexander Mikhalitsyn <[email protected]>--- arch/alpha/include/uapi/asm/socket.h | 2 ++ arch/mips/include/uapi/asm/socket.h | 2 ++ arch/parisc/include/uapi/asm/socket.h | 2 ++ arch/sparc/include/uapi/asm/socket.h | 2 ++ include/linux/net.h | 1 + include/linux/socket.h | 1 + include/net/scm.h | 39 +++++++++++++++++++++++-- include/uapi/asm-generic/socket.h | 2 ++ net/core/sock.c | 11 +++++++ net/mptcp/sockopt.c | 1 + net/unix/af_unix.c | 18 ++++++++---- tools/include/uapi/asm-generic/socket.h | 2 ++ 12 files changed, 76 insertions(+), 7 deletions(-)
...
Quoted 4 lines
include/net/scm.h +4
-0+static __inline__void scm_pidfd_recv (struct msghdr *msg,struct scm_cookie *scm) +{ +struct file *pidfd_file =NULL ; +int pidfd;
include/net/scm.h static inline bool scm_has_secdata(struct socket *sock) · line 136
Quoted 10 lines
include/net/scm.h +10
-0+ +/* +* put_cmsg() doesn't return an error if CMSG is truncated, +* that's why we need to opencode these checks here. +*/ +if ((msg->msg_controllen <=sizeof (struct cmsghdr )) || + (msg->msg_controllen -sizeof (struct cmsghdr )) <sizeof (int )) { + msg->msg_flags |=MSG_CTRUNC ; +return ; + }
This does not work for compat tasks since the size of struct cmsghdr (aka struct compat_cmsghdr) is differently. If the check from put_cmsg() is open-coded here, then also a different check for compat tasks needs to be added.
Discovered this because I was wondering why strace compat tests fail; it seems because of this.
See https://github.com/strace/strace/blob/master/tests/scm_pidfd.c
For compat tasks recvmsg() returns with msg_flags=MSG_CTRUNC since the above code expects a larger buffer than is necessary.
Re: [PATCH net-next v7 1/4] scm: add SO_PASSPIDFD and SCM_PIDFD
From: Heiko Carstens <[email protected]>
Date: Fri, 1 Sep 2023 22:05:17 +0200
Quoted 69 lines · Alexander Mikhalitsyn
Quoted 47 lines
Implement
SCM_PIDFD, a new type of CMSG type analogical toSCM_CREDENTIALS, but it contains pidfd instead of plain pid, which allows programmers not to care about PID reuse problem.We mask
SO_PASSPIDFDfeature ifCONFIG_UNIXis not builtin because it depends on apidfd_prepare()API which is not exported to the kernel modules.Idea comes from UAPI kernel group:
https://uapi-group.org/kernel-features/Big thanks to Christian Brauner and Lennart Poettering for productive discussions about this.
Cc "David S. Miller" <[email protected]>Cc Eric Dumazet <[email protected]>Cc Jakub Kicinski <[email protected]>Cc Paolo Abeni <[email protected]>Cc Leon Romanovsky <[email protected]>Cc David Ahern <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Kees Cook <[email protected]>Cc Christian Brauner <[email protected]>Cc Kuniyuki Iwashima <[email protected]>Cc Lennart Poettering <[email protected]>Cc Luca Boccassi <[email protected]>Tested-by Luca Boccassi <[email protected]>Reviewed-by Kuniyuki Iwashima <[email protected]>Reviewed-by Christian Brauner <[email protected]>Signed-off-by Alexander Mikhalitsyn <[email protected]>--- arch/alpha/include/uapi/asm/socket.h | 2 ++ arch/mips/include/uapi/asm/socket.h | 2 ++ arch/parisc/include/uapi/asm/socket.h | 2 ++ arch/sparc/include/uapi/asm/socket.h | 2 ++ include/linux/net.h | 1 + include/linux/socket.h | 1 + include/net/scm.h | 39 +++++++++++++++++++++++-- include/uapi/asm-generic/socket.h | 2 ++ net/core/sock.c | 11 +++++++ net/mptcp/sockopt.c | 1 + net/unix/af_unix.c | 18 ++++++++---- tools/include/uapi/asm-generic/socket.h | 2 ++ 12 files changed, 76 insertions(+), 7 deletions(-)...
Quoted 4 lines
(quoted diff) +4
-0+static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm) +{ + struct file *pidfd_file = NULL; + int pidfd;Review
Quoted 10 lines
(quoted diff) +10
-0+ + /* + * put_cmsg() doesn't return an error if CMSG is truncated, + * that's why we need to opencode these checks here. + */ + if ((msg->msg_controllen <= sizeof(struct cmsghdr)) || + (msg->msg_controllen - sizeof(struct cmsghdr)) < sizeof(int)) { + msg->msg_flags |= MSG_CTRUNC; + return; + }This does not work for compat tasks since the size of struct cmsghdr (aka struct
compat_cmsghdr) is differently. If the check fromput_cmsg()is open-coded here, then also a different check for compat tasks needs to be added.
Quoted 7 lines
Discovered this because I was wondering why strace compat tests fail; it seems because of this.
See https://github.com/strace/strace/blob/master/tests/scm_pidfd.c
For compat tasks
recvmsg()returns with msg_flags=MSG_CTRUNC since the above code expects a larger buffer than is necessary.
Can you test this ?
---8<---
include/net/scm.h +12 -6
@@ -9,6 +9,7 @@#include <linux/pid.h> #include <linux/nsproxy.h> #include <linux/sched/signal.h> +#include <net/compat.h> /* Well, we should have at least one descriptor open * to accept passed FDs 8)
@@ -125,14 +126,19 @@ static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scmstruct file *pidfd_file =NULL ;int pidfd; -/* -* put_cmsg() doesn't return an error if CMSG is truncated, +/* put_cmsg() doesn't return an error if CMSG is truncated, * that's why we need to opencode these checks here. */ -if ((msg->msg_controllen <=sizeof (struct cmsghdr )) || - (msg->msg_controllen -sizeof (struct cmsghdr )) <sizeof (int )) { - msg->msg_flags |=MSG_CTRUNC ; -return ; +if (msg->msg_flags &MSG_CMSG_COMPAT ) { +if (msg->msg_controllen <sizeof (struct compat_cmsghdr ) +sizeof (int )) { + msg->msg_flags |=MSG_CTRUNC ; +return ; + } + }else { +if (msg->msg_controllen <sizeof (struct cmsghdr ) +sizeof (int )) { + msg->msg_flags |=MSG_CTRUNC ; +return ; + } }if (!scm->pid)
---8<---
Heiko Carstens
Tested-byRe: [PATCH net-next v7 1/4] scm: add SO_PASSPIDFD and SCM_PIDFD
Quoted 17 lines · Kuniyuki Iwashima
From: Heiko Carstens <[email protected]>
Date: Fri, 1 Sep 2023 22:05:17 +0200Quoted 15 lines · Alexander Mikhalitsyn
include/net/scm.h static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm · line 136
Quoted 5 lines
include/net/scm.h +5
-0+if ((msg->msg_controllen <=sizeof (struct cmsghdr )) || + (msg->msg_controllen -sizeof (struct cmsghdr )) <sizeof (int )) { + msg->msg_flags |=MSG_CTRUNC ; +return ; + }This does not work for compat tasks since the size of struct cmsghdr (aka struct
compat_cmsghdr) is differently. If the check fromput_cmsg()is open-coded here, then also a different check for compat tasks needs to be added.Discovered this because I was wondering why strace compat tests fail; it seems because of this.
Quoted 6 lines
Quoted 4 lines
See https://github.com/strace/strace/blob/master/tests/scm_pidfd.c
For compat tasks
recvmsg()returns with msg_flags=MSG_CTRUNC since the above code expects a larger buffer than is necessary.Can you test this ?
Works for me.
Re: [PATCH net-next v7 1/4] scm: add SO_PASSPIDFD and SCM_PIDFD
From: Heiko Carstens <[email protected]>
Date: Fri, 1 Sep 2023 22:51:45 +0200
Quoted 20 lines · Kuniyuki Iwashima
Quoted 19 lines
From: Heiko Carstens <[email protected]>
Date: Fri, 1 Sep 2023 22:05:17 +0200Quoted 17 lines · Alexander Mikhalitsyn
include/net/scm.h static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm · line 136
Quoted 5 lines
include/net/scm.h +5
-0+if ((msg->msg_controllen <=sizeof (struct cmsghdr )) || + (msg->msg_controllen -sizeof (struct cmsghdr )) <sizeof (int )) { + msg->msg_flags |=MSG_CTRUNC ; +return ; + }This does not work for compat tasks since the size of struct cmsghdr (aka struct
compat_cmsghdr) is differently. If the check fromput_cmsg()is open-coded here, then also a different check for compat tasks needs to be added.Discovered this because I was wondering why strace compat tests fail; it seems because of this.
See https://github.com/strace/strace/blob/master/tests/scm_pidfd.c
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
For compat tasks
recvmsg()returns with msg_flags=MSG_CTRUNC since the above code expects a larger buffer than is necessary.Can you test this ?
Works for me.
Tested-by Heiko Carstens <[email protected]>
Thanks!
I'll post a formal patch.
Aleksandr Mikhalitsyn
Reviewed-byRe: [PATCH net-next v7 1/4] scm: add SO_PASSPIDFD and SCM_PIDFD
Quoted 31 lines · Kuniyuki Iwashima
From: Heiko Carstens <[email protected]>
Date: Fri, 1 Sep 2023 22:51:45 +0200Quoted 28 lines · Kuniyuki Iwashima
Quoted 17 lines
From: Heiko Carstens <[email protected]>
Date: Fri, 1 Sep 2023 22:05:17 +0200Quoted 15 lines · Alexander Mikhalitsyn
include/net/scm.h static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm · line 136
Quoted 5 lines
include/net/scm.h +5
-0+if ((msg->msg_controllen <=sizeof (struct cmsghdr )) || + (msg->msg_controllen -sizeof (struct cmsghdr )) <sizeof (int )) { + msg->msg_flags |=MSG_CTRUNC ; +return ; + }This does not work for compat tasks since the size of struct cmsghdr (aka struct
compat_cmsghdr) is differently. If the check fromput_cmsg()is open-coded here, then also a different check for compat tasks needs to be added.Discovered this because I was wondering why strace compat tests fail; it seems because of this.
Quoted 6 lines
Quoted 4 lines
See https://github.com/strace/strace/blob/master/tests/scm_pidfd.c
For compat tasks
recvmsg()returns with msg_flags=MSG_CTRUNC since the above code expects a larger buffer than is necessary.Can you test this ?
Works for me.
Tested-by Heiko Carstens <[email protected]>
Thanks for reporting this, Heiko!
My bad.
Kuniyuki,
Thanks for the quick fix.
Kind regards,
Alex
Quoted 3 lines
Thanks!
I'll post a formal patch.
PATCH v7 2/4 net: core: add getsockopt SO_PEERPIDFD
In reply to Alexander MikhalitsynAdd SO_PEERPIDFD which allows to get pidfd of peer socket holder pidfd. This thing is direct analog of SO_PEERCRED which allows to get plain PID.
---
v5:
- started using (struct proto)->bpf_bypass_getsockopt hook
v4:
- return -ESRCH if sk->sk_peer_pid is NULL from getsockopt() syscall
- return errors from pidfd_prepare() as it is from getsockopt() syscall
v3:
- fixed possible fd leak (thanks to Christian Brauner)
v2:
According to review comments from Kuniyuki Iwashima and Christian Brauner:
- use pidfd_create(..) retval as a result
- whitespace change
--- arch/alpha/include/uapi/asm/socket.h | 1 + arch/mips/include/uapi/asm/socket.h | 1 + arch/parisc/include/uapi/asm/socket.h | 1 + arch/sparc/include/uapi/asm/socket.h | 1 + include/uapi/asm-generic/socket.h | 1 + net/core/sock.c | 33 +++++++++++++++++++++++++ net/unix/af_unix.c | 16 ++++++++++++ tools/include/uapi/asm-generic/socket.h | 1 + 8 files changed, 55 insertions(+)
arch/alpha/include/uapi/asm/socket.h +1 -0
@@ -138,6 +138,7 @@#define SO_RCVMARK 75#define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77#if !defined(__KERNEL__)
arch/mips/include/uapi/asm/socket.h +1 -0
@@ -149,6 +149,7 @@#define SO_RCVMARK 75#define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77#if !defined(__KERNEL__)
arch/parisc/include/uapi/asm/socket.h +1 -0
@@ -130,6 +130,7 @@#define SO_RCVMARK 0x4049#define SO_PASSPIDFD 0x404A +#define SO_PEERPIDFD 0x404B#if !defined(__KERNEL__)
arch/sparc/include/uapi/asm/socket.h +1 -0
@@ -131,6 +131,7 @@#define SO_RCVMARK 0x0054#define SO_PASSPIDFD 0x0055 +#define SO_PEERPIDFD 0x0056#if !defined(__KERNEL__)
include/uapi/asm-generic/socket.h +1 -0
@@ -133,6 +133,7 @@#define SO_RCVMARK 75#define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77#if !defined(__KERNEL__)
net/core/sock.c +33 -0
@@ -1758,6 +1758,39 @@ int sk_getsockopt(struct sock *sk, int level, int optname, goto lenout; } +case SO_PEERPIDFD : + { +struct pid *peer_pid; +struct file *pidfd_file =NULL ; +int pidfd; + +if (len >sizeof (pidfd)) + len =sizeof (pidfd); + +spin_lock (&sk->sk_peer_lock); + peer_pid =get_pid (sk->sk_peer_pid); +spin_unlock (&sk->sk_peer_lock); + +if (!peer_pid) +return -ESRCH ; + + pidfd =pidfd_prepare (peer_pid,0 , &pidfd_file); +put_pid (peer_pid); +if (pidfd <0 ) +return pidfd; + +if (copy_to_sockptr (optval, &pidfd, len) || +copy_to_sockptr (optlen, &len,sizeof (int ))) { +put_unused_fd (pidfd); +fput (pidfd_file); + +return -EFAULT ; + } + +fd_install (pidfd, pidfd_file); +return 0 ; + } +case SO_PEERGROUPS : {const struct cred *cred;
net/unix/af_unix.c +16 -0
@@ -921,11 +921,26 @@ static void unix_unhash(struct sock *sk)*/ } +static bool unix_bpf_bypass_getsockopt (int level,int optname) +{ +if (level ==SOL_SOCKET ) { +switch (optname) { +case SO_PEERPIDFD : +return true; +default : +return false; + } + } + +return false; +} +struct proto unix_dgram_proto = { .name ="UNIX" , .owner =THIS_MODULE , .obj_size =sizeof (struct unix_sock ), .close = unix_close, + .bpf_bypass_getsockopt = unix_bpf_bypass_getsockopt, #ifdef CONFIG_BPF_SYSCALL .psock_update_sk_prot = unix_dgram_bpf_update_proto, #endif
@@ -937,6 +952,7 @@ struct proto unix_stream_proto = { .obj_size = sizeof(struct unix_sock), .close = unix_close, .unhash = unix_unhash, + .bpf_bypass_getsockopt = unix_bpf_bypass_getsockopt,#ifdef CONFIG_BPF_SYSCALL .psock_update_sk_prot = unix_stream_bpf_update_proto,#endif
tools/include/uapi/asm-generic/socket.h +1 -0
@@ -122,6 +122,7 @@#define SO_RCVMARK 75#define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77#if !defined(__KERNEL__)
Signature · 1 line
2.34.1
Re: [PATCH net-next v7 2/4] net: core: add getsockopt SO_PEERPIDFD
Quoted 18 lines · Alexander Mikhalitsyn
Add
SO_PEERPIDFDwhich allows to get pidfd of peer socket holder pidfd. This thing is direct analog ofSO_PEERCREDwhich allows to get plain PID.Cc "David S. Miller" <[email protected]>Cc Eric Dumazet <[email protected]>Cc Jakub Kicinski <[email protected]>Cc Paolo Abeni <[email protected]>Cc Leon Romanovsky <[email protected]>Cc David Ahern <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Kees Cook <[email protected]>Cc Christian Brauner <[email protected]>Cc Kuniyuki Iwashima <[email protected]>Cc Lennart Poettering <[email protected]>Cc Luca Boccassi <[email protected]>Cc Daniel Borkmann <[email protected]>Cc Stanislav Fomichev <[email protected]>
Quoted 9 lines
Reviewed-by Christian Brauner <[email protected]>Tested-by Luca Boccassi <[email protected]>Signed-off-by Alexander Mikhalitsyn <[email protected]>
PATCH v7 3/4 selftests: net: add SCM_PIDFD / SO_PEERPIDFD test
In reply to Alexander MikhalitsynBasic test to check consistency between:
- SCM_CREDENTIALS and SCM_PIDFD
- SO_PEERCRED and SO_PEERPIDFD
---
v3:
- started using kselftest lib (thanks to Kuniyuki Iwashima for suggestion/review)
- now test covers abstract sockets too and SOCK_DGRAM sockets
--- tools/testing/selftests/net/.gitignore | 1 + tools/testing/selftests/net/af_unix/Makefile | 3 +- .../testing/selftests/net/af_unix/scm_pidfd.c | 430 ++++++++++++++++++ 3 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/net/af_unix/scm_pidfd.c
tools/testing/selftests/net/.gitignore +1 -0
@@ -29,6 +29,7 @@ reuseport_bpf_numa reuseport_dualstack rxtimestamp sctp_hello +scm_pidfd sk_bind_sendto_listen sk_connect_zero_addr socket
tools/testing/selftests/net/af_unix/Makefile +2 -1
@@ -1,3 +1,4 @@ -TEST_GEN_PROGS := diag_uid test_unix_oob unix_connect +CFLAGS += $(KHDR_INCLUDES) +TEST_GEN_PROGS := diag_uid test_unix_oob unix_connect scm_pidfd include ../../lib.mk
tools/testing/selftests/net/af_unix/scm_pidfd.c new file +430 -0
430 lines not on this page · raw message
Signature · 1 line
2.34.1
PATCH v7 4/4 af_unix: Kconfig: make CONFIG_UNIX bool
In reply to Alexander MikhalitsynLet's make CONFIG_UNIX a bool instead of a tristate.
We've decided to do that during discussion about SCM_PIDFD patchset [1].
[1] https://lore.kernel.org/lkml/[email protected]/
--- net/unix/Kconfig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
net/unix/Kconfig +1 -5
@@ -4,7 +4,7 @@ # config UNIX - tristate "Unix domain sockets" + bool "Unix domain sockets" help If you say Y here, you will include support for Unix domain sockets; sockets are the standard Unix mechanism for establishing and
@@ -14,10 +14,6 @@ config UNIX an embedded system or something similar, you therefore definitely want to say Y here. - To compile this driver as a module, choose M here: the module will be - called unix. Note that several important services won't work - correctly if you say M here and then neglect to load the module. - Say Y unless you know what you are doing. config UNIX_SCM
Signature · 1 line
2.34.1
Re: [PATCH net-next v7 4/4] af_unix: Kconfig: make CONFIG_UNIX bool
Quoted 22 lines · Alexander Mikhalitsyn
Let's make
CONFIG_UNIXa bool instead of a tristate.
We've decided to do that during discussion aboutSCM_PIDFDpatchset [1].[1] https://lore.kernel.org/lkml/[email protected]/
Cc "David S. Miller" <[email protected]>Cc Eric Dumazet <[email protected]>Cc Jakub Kicinski <[email protected]>Cc Paolo Abeni <[email protected]>Cc Leon Romanovsky <[email protected]>Cc David Ahern <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Kees Cook <[email protected]>Cc Christian Brauner <[email protected]>Cc Kuniyuki Iwashima <[email protected]>Cc Lennart Poettering <[email protected]>Cc Luca Boccassi <[email protected]>Suggested-by Jakub Kicinski <[email protected]>Signed-off-by Alexander Mikhalitsyn <[email protected]>
Quoted 1 line
---
Looks good to me,
Re: [PATCH net-next v7 4/4] af_unix: Kconfig: make CONFIG_UNIX bool
In reply to Alexander MikhalitsynQuoted 15 lines · Alexander Mikhalitsyn
Let's make
CONFIG_UNIXa bool instead of a tristate.
We've decided to do that during discussion aboutSCM_PIDFDpatchset [1].[1] https://lore.kernel.org/lkml/[email protected]/
Cc "David S. Miller" <[email protected]>Cc Eric Dumazet <[email protected]>Cc Jakub Kicinski <[email protected]>Cc Paolo Abeni <[email protected]>Cc Leon Romanovsky <[email protected]>Cc David Ahern <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Kees Cook <[email protected]>Cc Christian Brauner <[email protected]>
Quoted 8 lines
Cc Kuniyuki Iwashima <[email protected]>Cc Lennart Poettering <[email protected]>Cc Luca Boccassi <[email protected]>Suggested-by Jakub Kicinski <[email protected]>Signed-off-by Alexander Mikhalitsyn <[email protected]>
This series was applied to netdev/net-next.git (main) by David S. Miller <[email protected]>:
Hello:
This series was applied to netdev/net-next.git (main) by David S. Miller <[email protected]>:
Quoted 8 lines · On Thu, 8 Jun 2023 22:26:24 +0200 you wrote:
1. Implement
SCM_PIDFD, a new type of CMSG type analogical toSCM_CREDENTIALS, but it contains pidfd instead of plain pid, which allows programmers not to care about PID reuse problem.2. Add
SO_PEERPIDFDwhich allows to get pidfd of peer socket holder pidfd. This thing is direct analog ofSO_PEERCREDwhich allows to get plain PID.[...]
Here is the summary with links:
- [net-next,v7,1/4] scm: add SO_PASSPIDFD and SCM_PIDFD
https://git.kernel.org/netdev/net-next/c/5e2ff6704a27 - [net-next,v7,2/4] net: core: add getsockopt SO_PEERPIDFD https://git.kernel.org/netdev/net-next/c/7b26952a91cf - [net-next,v7,3/4] selftests: net: add SCM_PIDFD / SO_PEERPIDFD test https://git.kernel.org/netdev/net-next/c/ec80f488252b - [net-next,v7,4/4] af_unix: Kconfig: make CONFIG_UNIX bool https://git.kernel.org/netdev/net-next/c/97154bcf4d1b
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html