All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 0/3] Add SCM_PIDFD and SO_PEERPIDFD
@ 2023-03-16 13:15 Alexander Mikhalitsyn
  2023-03-16 13:15 ` [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD Alexander Mikhalitsyn
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Alexander Mikhalitsyn @ 2023-03-16 13:15 UTC (permalink / raw)
  To: davem
  Cc: linux-kernel, netdev, Alexander Mikhalitsyn, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Leon Romanovsky, David Ahern,
	Arnd Bergmann, Kees Cook, Christian Brauner

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.

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: Leon Romanovsky <leon@kernel.org>
Cc: David Ahern <dsahern@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Kees Cook <keescook@chromium.org>
Cc: Christian Brauner <brauner@kernel.org>

Alexander Mikhalitsyn (3):
  scm: add SO_PASSPIDFD and SCM_PIDFD
  net: core: add getsockopt SO_PEERPIDFD
  selftests: net: add SCM_PIDFD / SO_PEERPIDFD test

 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                             |  16 +-
 include/uapi/asm-generic/socket.h             |   3 +
 net/core/sock.c                               |  35 ++
 net/mptcp/sockopt.c                           |   1 +
 net/unix/af_unix.c                            |  18 +-
 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 | 336 ++++++++++++++++++
 15 files changed, 423 insertions(+), 7 deletions(-)
 create mode 100644 tools/testing/selftests/net/af_unix/scm_pidfd.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD
  2023-03-16 13:15 [PATCH net-next 0/3] Add SCM_PIDFD and SO_PEERPIDFD Alexander Mikhalitsyn
@ 2023-03-16 13:15 ` Alexander Mikhalitsyn
  2023-03-16 14:34   ` Eric Dumazet
                     ` (2 more replies)
  2023-03-16 13:15 ` [PATCH net-next 2/3] net: core: add getsockopt SO_PEERPIDFD Alexander Mikhalitsyn
                   ` (2 subsequent siblings)
  3 siblings, 3 replies; 15+ messages in thread
From: Alexander Mikhalitsyn @ 2023-03-16 13:15 UTC (permalink / raw)
  To: davem
  Cc: linux-kernel, netdev, Alexander Mikhalitsyn, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Leon Romanovsky, David Ahern,
	Arnd Bergmann, Kees Cook, Christian Brauner, linux-arch

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.

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: Leon Romanovsky <leon@kernel.org>
Cc: David Ahern <dsahern@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Kees Cook <keescook@chromium.org>
Cc: Christian Brauner <brauner@kernel.org>
Cc: linux-kernel@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: linux-arch@vger.kernel.org
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
---
 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                       | 16 +++++++++++++++-
 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, 54 insertions(+), 6 deletions(-)

diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
index 739891b94136..ff310613ae64 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -137,6 +137,8 @@
 
 #define SO_RCVMARK		75
 
+#define SO_PASSPIDFD		76
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index 18f3d95ecfec..762dcb80e4ec 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -148,6 +148,8 @@
 
 #define SO_RCVMARK		75
 
+#define SO_PASSPIDFD		76
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
index f486d3dfb6bb..df16a3e16d64 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -129,6 +129,8 @@
 
 #define SO_RCVMARK		0x4049
 
+#define SO_PASSPIDFD		0x404A
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index 2fda57a3ea86..6e2847804fea 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -130,6 +130,8 @@
 
 #define SO_RCVMARK               0x0054
 
+#define SO_PASSPIDFD             0x0055
+
 #if !defined(__KERNEL__)
 
 
diff --git a/include/linux/net.h b/include/linux/net.h
index b73ad8e3c212..c234dfbe7a30 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -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
 /**
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 13c3a237b9c9..6bf90f251910 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -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;
diff --git a/include/net/scm.h b/include/net/scm.h
index 585adc1346bd..4617fbc65294 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -124,7 +124,9 @@ 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 ||
+		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);
@@ -141,6 +143,18 @@ 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)) {
+		int pidfd;
+
+		if (WARN_ON_ONCE(!scm->pid) ||
+		    !pid_has_task(scm->pid, PIDTYPE_TGID))
+			pidfd = -ESRCH;
+		else
+			pidfd = pidfd_create(scm->pid, 0);
+
+		put_cmsg(msg, SOL_SOCKET, SCM_PIDFD, sizeof(int), &pidfd);
+	}
+
 	scm_destroy_cred(scm);
 
 	scm_passec(sock, msg, scm);
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index 638230899e98..b76169fdb80b 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -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__))
diff --git a/net/core/sock.c b/net/core/sock.c
index c25888795390..3f974246ba3e 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -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:
@@ -1737,6 +1744,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;
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index 8a9656248b0f..bd80e707d0b3 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -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:
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 0b0f18ecce44..b0ac768752fa 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -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);
 }
 
 /*
@@ -1922,7 +1928,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;
@@ -2824,7 +2831,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);
diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h
index 8756df13be50..fbbc4bf53ee3 100644
--- a/tools/include/uapi/asm-generic/socket.h
+++ b/tools/include/uapi/asm-generic/socket.h
@@ -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__))
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next 2/3] net: core: add getsockopt SO_PEERPIDFD
  2023-03-16 13:15 [PATCH net-next 0/3] Add SCM_PIDFD and SO_PEERPIDFD Alexander Mikhalitsyn
  2023-03-16 13:15 ` [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD Alexander Mikhalitsyn
@ 2023-03-16 13:15 ` Alexander Mikhalitsyn
  2023-03-17  5:55   ` Kuniyuki Iwashima
  2023-03-17  9:08   ` Christian Brauner
  2023-03-16 13:15 ` [PATCH net-next 3/3] selftests: net: add SCM_PIDFD / SO_PEERPIDFD test Alexander Mikhalitsyn
  2023-03-20 14:35 ` [PATCH net-next 0/3] Add SCM_PIDFD and SO_PEERPIDFD Luca Boccassi
  3 siblings, 2 replies; 15+ messages in thread
From: Alexander Mikhalitsyn @ 2023-03-16 13:15 UTC (permalink / raw)
  To: davem
  Cc: linux-kernel, netdev, Alexander Mikhalitsyn, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Leon Romanovsky, David Ahern,
	Arnd Bergmann, Kees Cook, Christian Brauner, linux-arch

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.

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: Leon Romanovsky <leon@kernel.org>
Cc: David Ahern <dsahern@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Kees Cook <keescook@chromium.org>
Cc: Christian Brauner <brauner@kernel.org>
Cc: linux-kernel@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: linux-arch@vger.kernel.org
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
---
 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                         | 24 ++++++++++++++++++++++++
 tools/include/uapi/asm-generic/socket.h |  1 +
 7 files changed, 30 insertions(+)

diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
index ff310613ae64..e94f621903fe 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -138,6 +138,7 @@
 #define SO_RCVMARK		75
 
 #define SO_PASSPIDFD		76
+#define SO_PEERPIDFD		77
 
 #if !defined(__KERNEL__)
 
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index 762dcb80e4ec..60ebaed28a4c 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -149,6 +149,7 @@
 #define SO_RCVMARK		75
 
 #define SO_PASSPIDFD		76
+#define SO_PEERPIDFD		77
 
 #if !defined(__KERNEL__)
 
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
index df16a3e16d64..be264c2b1a11 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -130,6 +130,7 @@
 #define SO_RCVMARK		0x4049
 
 #define SO_PASSPIDFD		0x404A
+#define SO_PEERPIDFD		0x404B
 
 #if !defined(__KERNEL__)
 
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index 6e2847804fea..682da3714686 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -131,6 +131,7 @@
 #define SO_RCVMARK               0x0054
 
 #define SO_PASSPIDFD             0x0055
+#define SO_PEERPIDFD             0x0056
 
 #if !defined(__KERNEL__)
 
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index b76169fdb80b..8ce8a39a1e5f 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -133,6 +133,7 @@
 #define SO_RCVMARK		75
 
 #define SO_PASSPIDFD		76
+#define SO_PEERPIDFD		77
 
 #if !defined(__KERNEL__)
 
diff --git a/net/core/sock.c b/net/core/sock.c
index 3f974246ba3e..3aa1ccd4bcf3 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1763,6 +1763,30 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
 		goto lenout;
 	}
 
+	case SO_PEERPIDFD:
+	{
+		struct pid *peer_pid;
+		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 ||
+		    !pid_has_task(peer_pid, PIDTYPE_TGID))
+			pidfd = -ESRCH;
+		else
+			pidfd = pidfd_create(peer_pid, 0);
+
+		put_pid(peer_pid);
+
+		if (copy_to_sockptr(optval, &pidfd, len))
+			return -EFAULT;
+		goto lenout;
+	}
+
 	case SO_PEERGROUPS:
 	{
 		const struct cred *cred;
diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h
index fbbc4bf53ee3..54d9c8bf7c55 100644
--- a/tools/include/uapi/asm-generic/socket.h
+++ b/tools/include/uapi/asm-generic/socket.h
@@ -122,6 +122,7 @@
 #define SO_RCVMARK		75
 
 #define SO_PASSPIDFD		76
+#define SO_PEERPIDFD		77
 
 #if !defined(__KERNEL__)
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next 3/3] selftests: net: add SCM_PIDFD / SO_PEERPIDFD test
  2023-03-16 13:15 [PATCH net-next 0/3] Add SCM_PIDFD and SO_PEERPIDFD Alexander Mikhalitsyn
  2023-03-16 13:15 ` [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD Alexander Mikhalitsyn
  2023-03-16 13:15 ` [PATCH net-next 2/3] net: core: add getsockopt SO_PEERPIDFD Alexander Mikhalitsyn
@ 2023-03-16 13:15 ` Alexander Mikhalitsyn
  2023-03-20 14:35 ` [PATCH net-next 0/3] Add SCM_PIDFD and SO_PEERPIDFD Luca Boccassi
  3 siblings, 0 replies; 15+ messages in thread
From: Alexander Mikhalitsyn @ 2023-03-16 13:15 UTC (permalink / raw)
  To: davem
  Cc: linux-kernel, netdev, Alexander Mikhalitsyn, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Leon Romanovsky, David Ahern,
	Arnd Bergmann, Kees Cook, Christian Brauner, linux-arch,
	linux-kselftest

Basic test to check consistency between:
- SCM_CREDENTIALS and SCM_PIDFD
- SO_PEERCRED and SO_PEERPIDFD

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: Leon Romanovsky <leon@kernel.org>
Cc: David Ahern <dsahern@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Kees Cook <keescook@chromium.org>
Cc: Christian Brauner <brauner@kernel.org>
Cc: linux-kernel@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: linux-arch@vger.kernel.org
Cc: linux-kselftest@vger.kernel.org
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
---
 tools/testing/selftests/net/.gitignore        |   1 +
 tools/testing/selftests/net/af_unix/Makefile  |   3 +-
 .../testing/selftests/net/af_unix/scm_pidfd.c | 336 ++++++++++++++++++
 3 files changed, 339 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/net/af_unix/scm_pidfd.c

diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore
index a6911cae368c..f2d23a1df596 100644
--- a/tools/testing/selftests/net/.gitignore
+++ b/tools/testing/selftests/net/.gitignore
@@ -25,6 +25,7 @@ reuseport_bpf_cpu
 reuseport_bpf_numa
 reuseport_dualstack
 rxtimestamp
+scm_pidfd
 sk_bind_sendto_listen
 sk_connect_zero_addr
 socket
diff --git a/tools/testing/selftests/net/af_unix/Makefile b/tools/testing/selftests/net/af_unix/Makefile
index 1e4b397cece6..221c387a7d7f 100644
--- a/tools/testing/selftests/net/af_unix/Makefile
+++ b/tools/testing/selftests/net/af_unix/Makefile
@@ -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
diff --git a/tools/testing/selftests/net/af_unix/scm_pidfd.c b/tools/testing/selftests/net/af_unix/scm_pidfd.c
new file mode 100644
index 000000000000..fa502510ee9e
--- /dev/null
+++ b/tools/testing/selftests/net/af_unix/scm_pidfd.c
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <error.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <linux/socket.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/un.h>
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define clean_errno() (errno == 0 ? "None" : strerror(errno))
+#define log_err(MSG, ...)                                                   \
+	fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", __FILE__, __LINE__, \
+		clean_errno(), ##__VA_ARGS__)
+
+#ifndef SCM_PIDFD
+#define SCM_PIDFD 0x04
+#endif
+
+static pid_t client_pid;
+static char sock_name[32];
+
+static void die(int status)
+{
+	unlink(sock_name);
+	kill(client_pid, SIGTERM);
+	exit(status);
+}
+
+static void child_die()
+{
+	kill(getppid(), SIGTERM);
+	exit(1);
+}
+
+static int safe_int(const char *numstr, int *converted)
+{
+	char *err = NULL;
+	long sli;
+
+	errno = 0;
+	sli = strtol(numstr, &err, 0);
+	if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
+		return -ERANGE;
+
+	if (errno != 0 && sli == 0)
+		return -EINVAL;
+
+	if (err == numstr || *err != '\0')
+		return -EINVAL;
+
+	if (sli > INT_MAX || sli < INT_MIN)
+		return -ERANGE;
+
+	*converted = (int)sli;
+	return 0;
+}
+
+static int char_left_gc(const char *buffer, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (buffer[i] == ' ' || buffer[i] == '\t')
+			continue;
+
+		return i;
+	}
+
+	return 0;
+}
+
+static int char_right_gc(const char *buffer, size_t len)
+{
+	int i;
+
+	for (i = len - 1; i >= 0; i--) {
+		if (buffer[i] == ' ' || buffer[i] == '\t' ||
+		    buffer[i] == '\n' || buffer[i] == '\0')
+			continue;
+
+		return i + 1;
+	}
+
+	return 0;
+}
+
+static char *trim_whitespace_in_place(char *buffer)
+{
+	buffer += char_left_gc(buffer, strlen(buffer));
+	buffer[char_right_gc(buffer, strlen(buffer))] = '\0';
+	return buffer;
+}
+
+/* borrowed (with all helpers) from pidfd/pidfd_open_test.c */
+static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t keylen)
+{
+	int ret;
+	char path[512];
+	FILE *f;
+	size_t n = 0;
+	pid_t result = -1;
+	char *line = NULL;
+
+	snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd);
+
+	f = fopen(path, "re");
+	if (!f)
+		return -1;
+
+	while (getline(&line, &n, f) != -1) {
+		char *numstr;
+
+		if (strncmp(line, key, keylen))
+			continue;
+
+		numstr = trim_whitespace_in_place(line + 4);
+		ret = safe_int(numstr, &result);
+		if (ret < 0)
+			goto out;
+
+		break;
+	}
+
+out:
+	free(line);
+	fclose(f);
+	return result;
+}
+
+static int cmsg_check(int fd)
+{
+	struct msghdr msg = { 0 };
+	struct cmsghdr *cmsg;
+	struct iovec iov;
+	struct ucred *ucred = NULL;
+	int data = 0;
+	char control[CMSG_SPACE(sizeof(struct ucred)) +
+		     CMSG_SPACE(sizeof(int))] = { 0 };
+	int *pidfd = NULL;
+	pid_t parent_pid;
+	int err;
+
+	iov.iov_base = &data;
+	iov.iov_len = sizeof(data);
+
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = control;
+	msg.msg_controllen = sizeof(control);
+
+	err = recvmsg(fd, &msg, 0);
+	if (err < 0) {
+		log_err("recvmsg");
+		return 1;
+	}
+
+	if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) {
+		log_err("recvmsg: truncated");
+		return 1;
+	}
+
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+	     cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+		if (cmsg->cmsg_level == SOL_SOCKET &&
+		    cmsg->cmsg_type == SCM_PIDFD) {
+			if (cmsg->cmsg_len < sizeof(*pidfd)) {
+				log_err("CMSG parse: SCM_PIDFD wrong len");
+				return 1;
+			}
+
+			pidfd = (void *)CMSG_DATA(cmsg);
+		}
+
+		if (cmsg->cmsg_level == SOL_SOCKET &&
+		    cmsg->cmsg_type == SCM_CREDENTIALS) {
+			if (cmsg->cmsg_len < sizeof(*ucred)) {
+				log_err("CMSG parse: SCM_CREDENTIALS wrong len");
+				return 1;
+			}
+
+			ucred = (void *)CMSG_DATA(cmsg);
+		}
+	}
+
+	/* send(pfd, "x", sizeof(char), 0) */
+	if (data != 'x') {
+		log_err("recvmsg: data corruption");
+		return 1;
+	}
+
+	if (!pidfd) {
+		log_err("CMSG parse: SCM_PIDFD not found");
+		return 1;
+	}
+
+	if (!ucred) {
+		log_err("CMSG parse: SCM_CREDENTIALS not found");
+		return 1;
+	}
+
+	/* pidfd from SCM_PIDFD should point to the parent process PID */
+	parent_pid =
+		get_pid_from_fdinfo_file(*pidfd, "Pid:", sizeof("Pid:") - 1);
+	if (parent_pid != getppid()) {
+		log_err("wrong SCM_PIDFD %d != %d", parent_pid, getppid());
+		return 1;
+	}
+
+	return 0;
+}
+
+void client(struct sockaddr_un *listen_addr)
+{
+	int cfd;
+	socklen_t len;
+	struct ucred peer_cred;
+	int peer_pidfd;
+	pid_t peer_pid;
+	int on = 0;
+
+	cfd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (cfd < 0) {
+		log_err("socket");
+		child_die();
+	}
+
+	if (connect(cfd, (struct sockaddr *)listen_addr,
+		    sizeof(*listen_addr)) != 0) {
+		log_err("connect");
+		child_die();
+	}
+
+	on = 1;
+	if (setsockopt(cfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
+		log_err("Failed to set SO_PASSCRED");
+		child_die();
+	}
+
+	if (setsockopt(cfd, SOL_SOCKET, SO_PASSPIDFD, &on, sizeof(on))) {
+		log_err("Failed to set SO_PASSPIDFD");
+		child_die();
+	}
+
+	if (cmsg_check(cfd)) {
+		log_err("cmsg_check failed");
+		child_die();
+	}
+
+	len = sizeof(peer_cred);
+	if (getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &peer_cred, &len)) {
+		log_err("Failed to get SO_PEERCRED");
+		child_die();
+	}
+
+	len = sizeof(peer_pidfd);
+	if (getsockopt(cfd, SOL_SOCKET, SO_PEERPIDFD, &peer_pidfd, &len)) {
+		log_err("Failed to get SO_PEERPIDFD");
+		child_die();
+	}
+
+	/* pid from SO_PEERCRED should point to the parent process PID */
+	if (peer_cred.pid != getppid()) {
+		log_err("Failed to get SO_PEERPIDFD");
+		child_die();
+	}
+
+	peer_pid = get_pid_from_fdinfo_file(peer_pidfd,
+					    "Pid:", sizeof("Pid:") - 1);
+	if (peer_pid != peer_cred.pid) {
+		log_err("Failed to get SO_PEERPIDFD");
+		child_die();
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int lfd, pfd;
+	int child_status = 0;
+	struct sockaddr_un listen_addr;
+
+	lfd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (lfd < 0) {
+		perror("socket");
+		exit(1);
+	}
+
+	memset(&listen_addr, 0, sizeof(listen_addr));
+	listen_addr.sun_family = AF_UNIX;
+	sprintf(sock_name, "scm_pidfd_%d", getpid());
+	unlink(sock_name);
+	strcpy(listen_addr.sun_path, sock_name);
+
+	if ((bind(lfd, (struct sockaddr *)&listen_addr, sizeof(listen_addr))) !=
+	    0) {
+		perror("socket bind failed");
+		exit(1);
+	}
+
+	if (listen(lfd, 1) < 0) {
+		perror("listen");
+		exit(1);
+	}
+
+	client_pid = fork();
+	if (client_pid < 0) {
+		perror("fork");
+		exit(1);
+	}
+
+	if (client_pid == 0) {
+		client(&listen_addr);
+		exit(0);
+	}
+
+	pfd = accept(lfd, NULL, NULL);
+	if (pfd < 0) {
+		perror("accept");
+		die(1);
+	}
+
+	if (send(pfd, "x", sizeof(char), 0) < 0) {
+		perror("send");
+		die(1);
+	}
+
+	waitpid(client_pid, &child_status, 0);
+	die(WIFEXITED(child_status) ? WEXITSTATUS(child_status) : 1);
+	die(0);
+}
\ No newline at end of file
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD
  2023-03-16 13:15 ` [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD Alexander Mikhalitsyn
@ 2023-03-16 14:34   ` Eric Dumazet
  2023-03-16 15:32     ` Aleksandr Mikhalitsyn
  2023-03-16 23:50   ` kernel test robot
  2023-03-17  5:53   ` Kuniyuki Iwashima
  2 siblings, 1 reply; 15+ messages in thread
From: Eric Dumazet @ 2023-03-16 14:34 UTC (permalink / raw)
  To: Alexander Mikhalitsyn
  Cc: davem, linux-kernel, netdev, Jakub Kicinski, Paolo Abeni,
	Leon Romanovsky, David Ahern, Arnd Bergmann, Kees Cook,
	Christian Brauner, linux-arch

On Thu, Mar 16, 2023 at 6:16 AM Alexander Mikhalitsyn
<aleksandr.mikhalitsyn@canonical.com> wrote:
>
> 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.

Hi Alexander

This would add yet another conditional in af_unix fast path.

It seems that we already can use pidfd_open() (since linux-5.3), and
pass the resulting fd in af_unix SCM_RIGHTS message ?

If you think this is not suitable, it should at least be mentioned in
the changelog.

Thanks.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD
  2023-03-16 14:34   ` Eric Dumazet
@ 2023-03-16 15:32     ` Aleksandr Mikhalitsyn
  2023-03-17 10:20       ` Christian Brauner
  0 siblings, 1 reply; 15+ messages in thread
From: Aleksandr Mikhalitsyn @ 2023-03-16 15:32 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: davem, linux-kernel, netdev, Jakub Kicinski, Paolo Abeni,
	Leon Romanovsky, David Ahern, Arnd Bergmann, Kees Cook,
	Christian Brauner, linux-arch

On Thu, Mar 16, 2023 at 3:34 PM Eric Dumazet <edumazet@google.com> wrote:
>
> On Thu, Mar 16, 2023 at 6:16 AM Alexander Mikhalitsyn
> <aleksandr.mikhalitsyn@canonical.com> wrote:
> >
> > 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.
>
> Hi Alexander

Hi Eric

Thanks for the fast reply! ;-)

>
> This would add yet another conditional in af_unix fast path.
>
> It seems that we already can use pidfd_open() (since linux-5.3), and
> pass the resulting fd in af_unix SCM_RIGHTS message ?

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.

>
> If you think this is not suitable, it should at least be mentioned in
> the changelog.

Kind regards,
Alex

>
> Thanks.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD
  2023-03-16 13:15 ` [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD Alexander Mikhalitsyn
  2023-03-16 14:34   ` Eric Dumazet
@ 2023-03-16 23:50   ` kernel test robot
  2023-03-17  5:53   ` Kuniyuki Iwashima
  2 siblings, 0 replies; 15+ messages in thread
From: kernel test robot @ 2023-03-16 23:50 UTC (permalink / raw)
  To: Alexander Mikhalitsyn, davem
  Cc: oe-kbuild-all, linux-kernel, netdev, Alexander Mikhalitsyn,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Leon Romanovsky,
	David Ahern, Arnd Bergmann, Kees Cook, Christian Brauner,
	linux-arch

Hi Alexander,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Alexander-Mikhalitsyn/scm-add-SO_PASSPIDFD-and-SCM_PIDFD/20230316-214315
patch link:    https://lore.kernel.org/r/20230316131526.283569-2-aleksandr.mikhalitsyn%40canonical.com
patch subject: [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD
config: s390-buildonly-randconfig-r002-20230312 (https://download.01.org/0day-ci/archive/20230317/202303170733.ZQbJFE5x-lkp@intel.com/config)
compiler: s390-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/41687b4ae0dcef1fdffd656e533f9f35214043d0
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Alexander-Mikhalitsyn/scm-add-SO_PASSPIDFD-and-SCM_PIDFD/20230316-214315
        git checkout 41687b4ae0dcef1fdffd656e533f9f35214043d0
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=s390 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=s390 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202303170733.ZQbJFE5x-lkp@intel.com/

All errors (new ones prefixed by >>, old ones prefixed by <<):

ERROR: modpost: "devm_platform_ioremap_resource" [drivers/dma/idma64.ko] undefined!
>> ERROR: modpost: "pidfd_create" [net/unix/unix.ko] undefined!

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD
  2023-03-16 13:15 ` [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD Alexander Mikhalitsyn
  2023-03-16 14:34   ` Eric Dumazet
  2023-03-16 23:50   ` kernel test robot
@ 2023-03-17  5:53   ` Kuniyuki Iwashima
  2023-03-17  9:13     ` Christian Brauner
  2 siblings, 1 reply; 15+ messages in thread
From: Kuniyuki Iwashima @ 2023-03-17  5:53 UTC (permalink / raw)
  To: aleksandr.mikhalitsyn
  Cc: arnd, brauner, davem, dsahern, edumazet, keescook, kuba, leon,
	linux-arch, linux-kernel, netdev, pabeni, kuniyu

From:   Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Date:   Thu, 16 Mar 2023 14:15:24 +0100
> 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.
> 
> 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: Leon Romanovsky <leon@kernel.org>
> Cc: David Ahern <dsahern@kernel.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: Christian Brauner <brauner@kernel.org>
> Cc: linux-kernel@vger.kernel.org
> Cc: netdev@vger.kernel.org
> Cc: linux-arch@vger.kernel.org
> Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
> ---
>  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                       | 16 +++++++++++++++-
>  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, 54 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
> index 739891b94136..ff310613ae64 100644
> --- a/arch/alpha/include/uapi/asm/socket.h
> +++ b/arch/alpha/include/uapi/asm/socket.h
> @@ -137,6 +137,8 @@
>  
>  #define SO_RCVMARK		75
>  
> +#define SO_PASSPIDFD		76
> +
>  #if !defined(__KERNEL__)
>  
>  #if __BITS_PER_LONG == 64
> diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
> index 18f3d95ecfec..762dcb80e4ec 100644
> --- a/arch/mips/include/uapi/asm/socket.h
> +++ b/arch/mips/include/uapi/asm/socket.h
> @@ -148,6 +148,8 @@
>  
>  #define SO_RCVMARK		75
>  
> +#define SO_PASSPIDFD		76
> +
>  #if !defined(__KERNEL__)
>  
>  #if __BITS_PER_LONG == 64
> diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
> index f486d3dfb6bb..df16a3e16d64 100644
> --- a/arch/parisc/include/uapi/asm/socket.h
> +++ b/arch/parisc/include/uapi/asm/socket.h
> @@ -129,6 +129,8 @@
>  
>  #define SO_RCVMARK		0x4049
>  
> +#define SO_PASSPIDFD		0x404A
> +
>  #if !defined(__KERNEL__)
>  
>  #if __BITS_PER_LONG == 64
> diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
> index 2fda57a3ea86..6e2847804fea 100644
> --- a/arch/sparc/include/uapi/asm/socket.h
> +++ b/arch/sparc/include/uapi/asm/socket.h
> @@ -130,6 +130,8 @@
>  
>  #define SO_RCVMARK               0x0054
>  
> +#define SO_PASSPIDFD             0x0055
> +
>  #if !defined(__KERNEL__)
>  
>  
> diff --git a/include/linux/net.h b/include/linux/net.h
> index b73ad8e3c212..c234dfbe7a30 100644
> --- a/include/linux/net.h
> +++ b/include/linux/net.h
> @@ -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
>  /**
> diff --git a/include/linux/socket.h b/include/linux/socket.h
> index 13c3a237b9c9..6bf90f251910 100644
> --- a/include/linux/socket.h
> +++ b/include/linux/socket.h
> @@ -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;
> diff --git a/include/net/scm.h b/include/net/scm.h
> index 585adc1346bd..4617fbc65294 100644
> --- a/include/net/scm.h
> +++ b/include/net/scm.h
> @@ -124,7 +124,9 @@ 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 ||
> +		if (test_bit(SOCK_PASSCRED, &sock->flags) ||
> +		    test_bit(SOCK_PASSPIDFD, &sock->flags) ||
> +		    scm->fp ||

nit: I'd remove newline here.


>  		    scm_has_secdata(sock))
>  			msg->msg_flags |= MSG_CTRUNC;
>  		scm_destroy(scm);
> @@ -141,6 +143,18 @@ 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)) {
> +		int pidfd;
> +
> +		if (WARN_ON_ONCE(!scm->pid) ||
> +		    !pid_has_task(scm->pid, PIDTYPE_TGID))

Can we change pidfd_create() to return -ESRCH as it has the same test ?

> +			pidfd = -ESRCH;
> +		else
> +			pidfd = pidfd_create(scm->pid, 0);

Then we can change this part like:

    int pidfd = pidfd_create(scm->pid, 0);

    WARN_ON_ONCE(!scm->pid);


Thanks,
Kuniyuki


> +
> +		put_cmsg(msg, SOL_SOCKET, SCM_PIDFD, sizeof(int), &pidfd);
> +	}
> +
>  	scm_destroy_cred(scm);
>  
>  	scm_passec(sock, msg, scm);
> diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
> index 638230899e98..b76169fdb80b 100644
> --- a/include/uapi/asm-generic/socket.h
> +++ b/include/uapi/asm-generic/socket.h
> @@ -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__))
> diff --git a/net/core/sock.c b/net/core/sock.c
> index c25888795390..3f974246ba3e 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c
> @@ -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:
> @@ -1737,6 +1744,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;
> diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
> index 8a9656248b0f..bd80e707d0b3 100644
> --- a/net/mptcp/sockopt.c
> +++ b/net/mptcp/sockopt.c
> @@ -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:
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index 0b0f18ecce44..b0ac768752fa 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -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);
>  }
>  
>  /*
> @@ -1922,7 +1928,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;
> @@ -2824,7 +2831,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);
> diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h
> index 8756df13be50..fbbc4bf53ee3 100644
> --- a/tools/include/uapi/asm-generic/socket.h
> +++ b/tools/include/uapi/asm-generic/socket.h
> @@ -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__))
> -- 
> 2.34.1

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 2/3] net: core: add getsockopt SO_PEERPIDFD
  2023-03-16 13:15 ` [PATCH net-next 2/3] net: core: add getsockopt SO_PEERPIDFD Alexander Mikhalitsyn
@ 2023-03-17  5:55   ` Kuniyuki Iwashima
  2023-03-17  9:08   ` Christian Brauner
  1 sibling, 0 replies; 15+ messages in thread
From: Kuniyuki Iwashima @ 2023-03-17  5:55 UTC (permalink / raw)
  To: aleksandr.mikhalitsyn
  Cc: arnd, brauner, davem, dsahern, edumazet, keescook, kuba, leon,
	linux-arch, linux-kernel, netdev, pabeni, kuniyu

From:   Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Date:   Thu, 16 Mar 2023 14:15:25 +0100
> 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.
> 
> 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: Leon Romanovsky <leon@kernel.org>
> Cc: David Ahern <dsahern@kernel.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: Christian Brauner <brauner@kernel.org>
> Cc: linux-kernel@vger.kernel.org
> Cc: netdev@vger.kernel.org
> Cc: linux-arch@vger.kernel.org
> Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
> ---
>  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                         | 24 ++++++++++++++++++++++++
>  tools/include/uapi/asm-generic/socket.h |  1 +
>  7 files changed, 30 insertions(+)
> 
> diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
> index ff310613ae64..e94f621903fe 100644
> --- a/arch/alpha/include/uapi/asm/socket.h
> +++ b/arch/alpha/include/uapi/asm/socket.h
> @@ -138,6 +138,7 @@
>  #define SO_RCVMARK		75
>  
>  #define SO_PASSPIDFD		76
> +#define SO_PEERPIDFD		77
>  
>  #if !defined(__KERNEL__)
>  
> diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
> index 762dcb80e4ec..60ebaed28a4c 100644
> --- a/arch/mips/include/uapi/asm/socket.h
> +++ b/arch/mips/include/uapi/asm/socket.h
> @@ -149,6 +149,7 @@
>  #define SO_RCVMARK		75
>  
>  #define SO_PASSPIDFD		76
> +#define SO_PEERPIDFD		77
>  
>  #if !defined(__KERNEL__)
>  
> diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
> index df16a3e16d64..be264c2b1a11 100644
> --- a/arch/parisc/include/uapi/asm/socket.h
> +++ b/arch/parisc/include/uapi/asm/socket.h
> @@ -130,6 +130,7 @@
>  #define SO_RCVMARK		0x4049
>  
>  #define SO_PASSPIDFD		0x404A
> +#define SO_PEERPIDFD		0x404B
>  
>  #if !defined(__KERNEL__)
>  
> diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
> index 6e2847804fea..682da3714686 100644
> --- a/arch/sparc/include/uapi/asm/socket.h
> +++ b/arch/sparc/include/uapi/asm/socket.h
> @@ -131,6 +131,7 @@
>  #define SO_RCVMARK               0x0054
>  
>  #define SO_PASSPIDFD             0x0055
> +#define SO_PEERPIDFD             0x0056
>  
>  #if !defined(__KERNEL__)
>  
> diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
> index b76169fdb80b..8ce8a39a1e5f 100644
> --- a/include/uapi/asm-generic/socket.h
> +++ b/include/uapi/asm-generic/socket.h
> @@ -133,6 +133,7 @@
>  #define SO_RCVMARK		75
>  
>  #define SO_PASSPIDFD		76
> +#define SO_PEERPIDFD		77
>  
>  #if !defined(__KERNEL__)
>  
> diff --git a/net/core/sock.c b/net/core/sock.c
> index 3f974246ba3e..3aa1ccd4bcf3 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c
> @@ -1763,6 +1763,30 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
>  		goto lenout;
>  	}
>  
> +	case SO_PEERPIDFD:
> +	{
> +		struct pid *peer_pid;
> +		int pidfd;

nit: newline here, checkpatch.pl will complain.

> +		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 ||
> +		    !pid_has_task(peer_pid, PIDTYPE_TGID))
> +			pidfd = -ESRCH;
> +		else
> +			pidfd = pidfd_create(peer_pid, 0);

Same comment from patch 1.

                pidfd = pidfd_create(peer_pid, 0);


> +
> +		put_pid(peer_pid);
> +
> +		if (copy_to_sockptr(optval, &pidfd, len))
> +			return -EFAULT;
> +		goto lenout;
> +	}
> +
>  	case SO_PEERGROUPS:
>  	{
>  		const struct cred *cred;
> diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h
> index fbbc4bf53ee3..54d9c8bf7c55 100644
> --- a/tools/include/uapi/asm-generic/socket.h
> +++ b/tools/include/uapi/asm-generic/socket.h
> @@ -122,6 +122,7 @@
>  #define SO_RCVMARK		75
>  
>  #define SO_PASSPIDFD		76
> +#define SO_PEERPIDFD		77
>  
>  #if !defined(__KERNEL__)
>  
> -- 
> 2.34.1

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 2/3] net: core: add getsockopt SO_PEERPIDFD
  2023-03-16 13:15 ` [PATCH net-next 2/3] net: core: add getsockopt SO_PEERPIDFD Alexander Mikhalitsyn
  2023-03-17  5:55   ` Kuniyuki Iwashima
@ 2023-03-17  9:08   ` Christian Brauner
  1 sibling, 0 replies; 15+ messages in thread
From: Christian Brauner @ 2023-03-17  9:08 UTC (permalink / raw)
  To: Alexander Mikhalitsyn
  Cc: davem, linux-kernel, netdev, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Leon Romanovsky, David Ahern, Arnd Bergmann,
	Kees Cook, linux-arch

On Thu, Mar 16, 2023 at 02:15:25PM +0100, Alexander Mikhalitsyn wrote:
> 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.
> 
> 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: Leon Romanovsky <leon@kernel.org>
> Cc: David Ahern <dsahern@kernel.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: Christian Brauner <brauner@kernel.org>
> Cc: linux-kernel@vger.kernel.org
> Cc: netdev@vger.kernel.org
> Cc: linux-arch@vger.kernel.org
> Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
> ---
>  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                         | 24 ++++++++++++++++++++++++
>  tools/include/uapi/asm-generic/socket.h |  1 +
>  7 files changed, 30 insertions(+)
> 
> diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
> index ff310613ae64..e94f621903fe 100644
> --- a/arch/alpha/include/uapi/asm/socket.h
> +++ b/arch/alpha/include/uapi/asm/socket.h
> @@ -138,6 +138,7 @@
>  #define SO_RCVMARK		75
>  
>  #define SO_PASSPIDFD		76
> +#define SO_PEERPIDFD		77
>  
>  #if !defined(__KERNEL__)
>  
> diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
> index 762dcb80e4ec..60ebaed28a4c 100644
> --- a/arch/mips/include/uapi/asm/socket.h
> +++ b/arch/mips/include/uapi/asm/socket.h
> @@ -149,6 +149,7 @@
>  #define SO_RCVMARK		75
>  
>  #define SO_PASSPIDFD		76
> +#define SO_PEERPIDFD		77
>  
>  #if !defined(__KERNEL__)
>  
> diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
> index df16a3e16d64..be264c2b1a11 100644
> --- a/arch/parisc/include/uapi/asm/socket.h
> +++ b/arch/parisc/include/uapi/asm/socket.h
> @@ -130,6 +130,7 @@
>  #define SO_RCVMARK		0x4049
>  
>  #define SO_PASSPIDFD		0x404A
> +#define SO_PEERPIDFD		0x404B
>  
>  #if !defined(__KERNEL__)
>  
> diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
> index 6e2847804fea..682da3714686 100644
> --- a/arch/sparc/include/uapi/asm/socket.h
> +++ b/arch/sparc/include/uapi/asm/socket.h
> @@ -131,6 +131,7 @@
>  #define SO_RCVMARK               0x0054
>  
>  #define SO_PASSPIDFD             0x0055
> +#define SO_PEERPIDFD             0x0056
>  
>  #if !defined(__KERNEL__)
>  
> diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
> index b76169fdb80b..8ce8a39a1e5f 100644
> --- a/include/uapi/asm-generic/socket.h
> +++ b/include/uapi/asm-generic/socket.h
> @@ -133,6 +133,7 @@
>  #define SO_RCVMARK		75
>  
>  #define SO_PASSPIDFD		76
> +#define SO_PEERPIDFD		77
>  
>  #if !defined(__KERNEL__)
>  
> diff --git a/net/core/sock.c b/net/core/sock.c
> index 3f974246ba3e..3aa1ccd4bcf3 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c
> @@ -1763,6 +1763,30 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
>  		goto lenout;
>  	}
>  
> +	case SO_PEERPIDFD:
> +	{
> +		struct pid *peer_pid;
> +		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 ||
> +		    !pid_has_task(peer_pid, PIDTYPE_TGID))
> +			pidfd = -ESRCH;

Any specific reason you want -ESRCH here?
pidfd_create() returns -EINVAL for exactly this check it performs mainly
because the non-existence of PIDTYPE_TGID could either indicate that
this struct pid isn't used as a thread-group leader or - indeed - that
the process has already been reaped. IOW, if there's no specific reason
I would not deviate from pidfd_create()'s return value.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD
  2023-03-17  5:53   ` Kuniyuki Iwashima
@ 2023-03-17  9:13     ` Christian Brauner
  0 siblings, 0 replies; 15+ messages in thread
From: Christian Brauner @ 2023-03-17  9:13 UTC (permalink / raw)
  To: Kuniyuki Iwashima
  Cc: aleksandr.mikhalitsyn, arnd, davem, dsahern, edumazet, keescook,
	kuba, leon, linux-arch, linux-kernel, netdev, pabeni

On Thu, Mar 16, 2023 at 10:53:20PM -0700, Kuniyuki Iwashima wrote:
> From:   Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
> Date:   Thu, 16 Mar 2023 14:15:24 +0100
> > 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.
> > 
> > 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: Leon Romanovsky <leon@kernel.org>
> > Cc: David Ahern <dsahern@kernel.org>
> > Cc: Arnd Bergmann <arnd@arndb.de>
> > Cc: Kees Cook <keescook@chromium.org>
> > Cc: Christian Brauner <brauner@kernel.org>
> > Cc: linux-kernel@vger.kernel.org
> > Cc: netdev@vger.kernel.org
> > Cc: linux-arch@vger.kernel.org
> > Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
> > ---
> >  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                       | 16 +++++++++++++++-
> >  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, 54 insertions(+), 6 deletions(-)
> > 
> > diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
> > index 739891b94136..ff310613ae64 100644
> > --- a/arch/alpha/include/uapi/asm/socket.h
> > +++ b/arch/alpha/include/uapi/asm/socket.h
> > @@ -137,6 +137,8 @@
> >  
> >  #define SO_RCVMARK		75
> >  
> > +#define SO_PASSPIDFD		76
> > +
> >  #if !defined(__KERNEL__)
> >  
> >  #if __BITS_PER_LONG == 64
> > diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
> > index 18f3d95ecfec..762dcb80e4ec 100644
> > --- a/arch/mips/include/uapi/asm/socket.h
> > +++ b/arch/mips/include/uapi/asm/socket.h
> > @@ -148,6 +148,8 @@
> >  
> >  #define SO_RCVMARK		75
> >  
> > +#define SO_PASSPIDFD		76
> > +
> >  #if !defined(__KERNEL__)
> >  
> >  #if __BITS_PER_LONG == 64
> > diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
> > index f486d3dfb6bb..df16a3e16d64 100644
> > --- a/arch/parisc/include/uapi/asm/socket.h
> > +++ b/arch/parisc/include/uapi/asm/socket.h
> > @@ -129,6 +129,8 @@
> >  
> >  #define SO_RCVMARK		0x4049
> >  
> > +#define SO_PASSPIDFD		0x404A
> > +
> >  #if !defined(__KERNEL__)
> >  
> >  #if __BITS_PER_LONG == 64
> > diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
> > index 2fda57a3ea86..6e2847804fea 100644
> > --- a/arch/sparc/include/uapi/asm/socket.h
> > +++ b/arch/sparc/include/uapi/asm/socket.h
> > @@ -130,6 +130,8 @@
> >  
> >  #define SO_RCVMARK               0x0054
> >  
> > +#define SO_PASSPIDFD             0x0055
> > +
> >  #if !defined(__KERNEL__)
> >  
> >  
> > diff --git a/include/linux/net.h b/include/linux/net.h
> > index b73ad8e3c212..c234dfbe7a30 100644
> > --- a/include/linux/net.h
> > +++ b/include/linux/net.h
> > @@ -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
> >  /**
> > diff --git a/include/linux/socket.h b/include/linux/socket.h
> > index 13c3a237b9c9..6bf90f251910 100644
> > --- a/include/linux/socket.h
> > +++ b/include/linux/socket.h
> > @@ -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;
> > diff --git a/include/net/scm.h b/include/net/scm.h
> > index 585adc1346bd..4617fbc65294 100644
> > --- a/include/net/scm.h
> > +++ b/include/net/scm.h
> > @@ -124,7 +124,9 @@ 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 ||
> > +		if (test_bit(SOCK_PASSCRED, &sock->flags) ||
> > +		    test_bit(SOCK_PASSPIDFD, &sock->flags) ||
> > +		    scm->fp ||
> 
> nit: I'd remove newline here.
> 
> 
> >  		    scm_has_secdata(sock))
> >  			msg->msg_flags |= MSG_CTRUNC;
> >  		scm_destroy(scm);
> > @@ -141,6 +143,18 @@ 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)) {
> > +		int pidfd;
> > +
> > +		if (WARN_ON_ONCE(!scm->pid) ||
> > +		    !pid_has_task(scm->pid, PIDTYPE_TGID))
> 
> Can we change pidfd_create() to return -ESRCH as it has the same test ?

I don't think we can do this. pidfd_create() can't distinguish between
"this task has been reaped" and "this is a non-thread group leader". So
EINVAL is a better hint especially since pidfd_open() is preceeded by a
check that would return -ESRCH.

It would also be a uapi change for the pidfd_open() syscall to change
pidfd_create() like that and for fanotify as well. Now they get EINVAL
for a non-thread group leader pid they pass into the system call.
Afterwards they'd get ESRCH which is at least misleading if not wrong.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD
  2023-03-16 15:32     ` Aleksandr Mikhalitsyn
@ 2023-03-17 10:20       ` Christian Brauner
  2023-03-17 11:12         ` Lennart Poettering
  0 siblings, 1 reply; 15+ messages in thread
From: Christian Brauner @ 2023-03-17 10:20 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: davem, Aleksandr Mikhalitsyn, linux-kernel, netdev,
	Jakub Kicinski, Paolo Abeni, Leon Romanovsky, David Ahern,
	Arnd Bergmann, Kees Cook, linux-arch, Lennart Poettering

On Thu, Mar 16, 2023 at 04:32:03PM +0100, Aleksandr Mikhalitsyn wrote:
> On Thu, Mar 16, 2023 at 3:34 PM Eric Dumazet <edumazet@google.com> wrote:
> >
> > On Thu, Mar 16, 2023 at 6:16 AM Alexander Mikhalitsyn
> > <aleksandr.mikhalitsyn@canonical.com> wrote:
> > >
> > > 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.
> >
> > Hi Alexander
> 
> Hi Eric
> 
> Thanks for the fast reply! ;-)
> 
> >
> > This would add yet another conditional in af_unix fast path.
> >
> > It seems that we already can use pidfd_open() (since linux-5.3), and
> > pass the resulting fd in af_unix SCM_RIGHTS message ?
> 
> 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.
> 
> >
> > If you think this is not suitable, it should at least be mentioned in
> > the changelog.

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.

Link: https://gitlab.freedesktop.org/polkit/polkit/-/merge_requests/154
Link: https://uapi-group.org/kernel-features

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD
  2023-03-17 10:20       ` Christian Brauner
@ 2023-03-17 11:12         ` Lennart Poettering
  0 siblings, 0 replies; 15+ messages in thread
From: Lennart Poettering @ 2023-03-17 11:12 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Eric Dumazet, davem, Aleksandr Mikhalitsyn, linux-kernel, netdev,
	Jakub Kicinski, Paolo Abeni, Leon Romanovsky, David Ahern,
	Arnd Bergmann, Kees Cook, linux-arch

On Fr, 17.03.23 11:20, Christian Brauner (brauner@kernel.org) wrote:

> > > It seems that we already can use pidfd_open() (since linux-5.3), and
> > > pass the resulting fd in af_unix SCM_RIGHTS message ?

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_UNIX connection, 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.

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_UNIX transport. It's a seamless improvement of the status quo.

Lennart

--
Lennart Poettering, Berlin

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 0/3] Add SCM_PIDFD and SO_PEERPIDFD
  2023-03-16 13:15 [PATCH net-next 0/3] Add SCM_PIDFD and SO_PEERPIDFD Alexander Mikhalitsyn
                   ` (2 preceding siblings ...)
  2023-03-16 13:15 ` [PATCH net-next 3/3] selftests: net: add SCM_PIDFD / SO_PEERPIDFD test Alexander Mikhalitsyn
@ 2023-03-20 14:35 ` Luca Boccassi
  2023-03-27 11:18   ` Luca Boccassi
  3 siblings, 1 reply; 15+ messages in thread
From: Luca Boccassi @ 2023-03-20 14:35 UTC (permalink / raw)
  To: Alexander Mikhalitsyn, davem
  Cc: linux-kernel, netdev, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Leon Romanovsky, David Ahern, Arnd Bergmann, Kees Cook,
	Christian Brauner, smcv

[-- Attachment #1: Type: text/plain, Size: 1663 bytes --]

On Thu, 2023-03-16 at 14:15 +0100, Alexander Mikhalitsyn wrote:
> 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.
> 
> 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: Leon Romanovsky <leon@kernel.org>
> Cc: David Ahern <dsahern@kernel.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: Christian Brauner <brauner@kernel.org>
> 
> Alexander Mikhalitsyn (3):
>   scm: add SO_PASSPIDFD and SCM_PIDFD
>   net: core: add getsockopt SO_PEERPIDFD
>   selftests: net: add SCM_PIDFD / SO_PEERPIDFD test

I've implemented support for this in dbus-daemon:

https://gitlab.freedesktop.org/dbus/dbus/-/merge_requests/398

It's working very well. I am also working on the dbus-broker and polkit
side of things, will share the links here once they are in a reviewable
state. But the dbus-daemon implementation is enough to meaningfully
test this.

For the series:

Tested-by: Luca Boccassi <bluca@debian.org>

-- 
Kind regards,
Luca Boccassi

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 0/3] Add SCM_PIDFD and SO_PEERPIDFD
  2023-03-20 14:35 ` [PATCH net-next 0/3] Add SCM_PIDFD and SO_PEERPIDFD Luca Boccassi
@ 2023-03-27 11:18   ` Luca Boccassi
  0 siblings, 0 replies; 15+ messages in thread
From: Luca Boccassi @ 2023-03-27 11:18 UTC (permalink / raw)
  To: Alexander Mikhalitsyn, davem
  Cc: linux-kernel, netdev, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Leon Romanovsky, David Ahern, Arnd Bergmann, Kees Cook,
	Christian Brauner, smcv

On Mon, 20 Mar 2023 at 14:35, Luca Boccassi <bluca@debian.org> wrote:
>
> On Thu, 2023-03-16 at 14:15 +0100, Alexander Mikhalitsyn wrote:
> > 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.
> >
> > 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: Leon Romanovsky <leon@kernel.org>
> > Cc: David Ahern <dsahern@kernel.org>
> > Cc: Arnd Bergmann <arnd@arndb.de>
> > Cc: Kees Cook <keescook@chromium.org>
> > Cc: Christian Brauner <brauner@kernel.org>
> >
> > Alexander Mikhalitsyn (3):
> >   scm: add SO_PASSPIDFD and SCM_PIDFD
> >   net: core: add getsockopt SO_PEERPIDFD
> >   selftests: net: add SCM_PIDFD / SO_PEERPIDFD test
>
> I've implemented support for this in dbus-daemon:
>
> https://gitlab.freedesktop.org/dbus/dbus/-/merge_requests/398
>
> It's working very well. I am also working on the dbus-broker and polkit
> side of things, will share the links here once they are in a reviewable
> state. But the dbus-daemon implementation is enough to meaningfully
> test this.
>
> For the series:
>
> Tested-by: Luca Boccassi <bluca@debian.org>

Polkit changes:

https://gitlab.freedesktop.org/polkit/polkit/-/merge_requests/154

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2023-03-27 11:18 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-16 13:15 [PATCH net-next 0/3] Add SCM_PIDFD and SO_PEERPIDFD Alexander Mikhalitsyn
2023-03-16 13:15 ` [PATCH net-next 1/3] scm: add SO_PASSPIDFD and SCM_PIDFD Alexander Mikhalitsyn
2023-03-16 14:34   ` Eric Dumazet
2023-03-16 15:32     ` Aleksandr Mikhalitsyn
2023-03-17 10:20       ` Christian Brauner
2023-03-17 11:12         ` Lennart Poettering
2023-03-16 23:50   ` kernel test robot
2023-03-17  5:53   ` Kuniyuki Iwashima
2023-03-17  9:13     ` Christian Brauner
2023-03-16 13:15 ` [PATCH net-next 2/3] net: core: add getsockopt SO_PEERPIDFD Alexander Mikhalitsyn
2023-03-17  5:55   ` Kuniyuki Iwashima
2023-03-17  9:08   ` Christian Brauner
2023-03-16 13:15 ` [PATCH net-next 3/3] selftests: net: add SCM_PIDFD / SO_PEERPIDFD test Alexander Mikhalitsyn
2023-03-20 14:35 ` [PATCH net-next 0/3] Add SCM_PIDFD and SO_PEERPIDFD Luca Boccassi
2023-03-27 11:18   ` Luca Boccassi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.