netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS.
@ 2025-05-19 20:57 Kuniyuki Iwashima
  2025-05-19 20:57 ` [PATCH v5 net-next 1/9] af_unix: Factorise test_bit() for SOCK_PASSCRED and SOCK_PASSPIDFD Kuniyuki Iwashima
                   ` (9 more replies)
  0 siblings, 10 replies; 15+ messages in thread
From: Kuniyuki Iwashima @ 2025-05-19 20:57 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima,
	Kuniyuki Iwashima, netdev

As long as recvmsg() or recvmmsg() is used with cmsg, it is not
possible to avoid receiving file descriptors via SCM_RIGHTS.

This series introduces a new socket option, SO_PASSRIGHTS, to allow
disabling SCM_RIGHTS.  The option is enabled by default.

See patch 8 for background/context.

This series is related to [0], but is split into a separate series,
as most of the patches are specific to af_unix.

The v2 of the BPF LSM extension part will be posted later, once
this series is merged into net-next and has landed in bpf-next.

[0]: https://lore.kernel.org/bpf/20250505215802.48449-1-kuniyu@amazon.com/


Changes:
  v5:
    * Patch 4
      * Fix BPF selftest failure (setget_sockopt.c)

  v4: https://lore.kernel.org/netdev/20250515224946.6931-1-kuniyu@amazon.com/
    * Patch 6
      * Group sk->sk_scm_XXX bits by struct
    * Patch 9
      * Remove errno handling

  v3: https://lore.kernel.org/netdev/20250514165226.40410-1-kuniyu@amazon.com/
    * Patch 3
      * Remove inline in scm.c
    * Patch 4 & 5 & 8
      * Return -EOPNOTSUPP in getsockopt()
    * Patch 5
      * Add CONFIG_SECURITY_NETWORK check for SO_PASSSEC
    * Patch 6
      * Add kdoc for sk_scm_unused
      * Update sk_scm_XXX under lock_sock() in setsockopt()
    * Patch 7
      * Update changelog (recent change -> aed6ecef55d7)

  v2: https://lore.kernel.org/netdev/20250510015652.9931-1-kuniyu@amazon.com/
    * Added patch 4 & 5 to reuse sk_txrehash for scm_recv() flags

  v1: https://lore.kernel.org/netdev/20250508013021.79654-1-kuniyu@amazon.com/


Kuniyuki Iwashima (9):
  af_unix: Factorise test_bit() for SOCK_PASSCRED and SOCK_PASSPIDFD.
  af_unix: Don't pass struct socket to maybe_add_creds().
  scm: Move scm_recv() from scm.h to scm.c.
  tcp: Restrict SO_TXREHASH to TCP socket.
  net: Restrict SO_PASS{CRED,PIDFD,SEC} to AF_{UNIX,NETLINK,BLUETOOTH}.
  af_unix: Move SOCK_PASS{CRED,PIDFD,SEC} to struct sock.
  af_unix: Inherit sk_flags at connect().
  af_unix: Introduce SO_PASSRIGHTS.
  selftest: af_unix: Test SO_PASSRIGHTS.

 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                           |  15 +--
 include/net/scm.h                             | 121 +----------------
 include/net/sock.h                            |  32 ++++-
 include/uapi/asm-generic/socket.h             |   2 +
 net/core/scm.c                                | 122 ++++++++++++++++++
 net/core/sock.c                               |  63 +++++++--
 net/unix/af_unix.c                            |  96 +++++++-------
 tools/include/uapi/asm-generic/socket.h       |   2 +
 .../selftests/bpf/progs/setget_sockopt.c      |  11 ++
 .../selftests/net/af_unix/scm_rights.c        |  80 +++++++++++-
 14 files changed, 362 insertions(+), 190 deletions(-)

-- 
2.49.0


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

* [PATCH v5 net-next 1/9] af_unix: Factorise test_bit() for SOCK_PASSCRED and SOCK_PASSPIDFD.
  2025-05-19 20:57 [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
@ 2025-05-19 20:57 ` Kuniyuki Iwashima
  2025-05-19 20:57 ` [PATCH v5 net-next 2/9] af_unix: Don't pass struct socket to maybe_add_creds() Kuniyuki Iwashima
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Kuniyuki Iwashima @ 2025-05-19 20:57 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima,
	Kuniyuki Iwashima, netdev

Currently, the same checks for SOCK_PASSCRED and SOCK_PASSPIDFD
are scattered across many places.

Let's centralise the bit tests to make the following changes cleaner.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
 net/unix/af_unix.c | 37 +++++++++++++++----------------------
 1 file changed, 15 insertions(+), 22 deletions(-)

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 2ab20821d6bb..464e183ffdb8 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -765,6 +765,14 @@ static void copy_peercred(struct sock *sk, struct sock *peersk)
 	spin_unlock(&sk->sk_peer_lock);
 }
 
+static bool unix_may_passcred(const struct sock *sk)
+{
+	struct socket *sock = sk->sk_socket;
+
+	return test_bit(SOCK_PASSCRED, &sock->flags) ||
+		test_bit(SOCK_PASSPIDFD, &sock->flags);
+}
+
 static int unix_listen(struct socket *sock, int backlog)
 {
 	int err;
@@ -1411,9 +1419,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
 		if (err)
 			goto out;
 
-		if ((test_bit(SOCK_PASSCRED, &sock->flags) ||
-		     test_bit(SOCK_PASSPIDFD, &sock->flags)) &&
-		    !READ_ONCE(unix_sk(sk)->addr)) {
+		if (unix_may_passcred(sk) && !READ_ONCE(unix_sk(sk)->addr)) {
 			err = unix_autobind(sk);
 			if (err)
 				goto out;
@@ -1531,9 +1537,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 	if (err)
 		goto out;
 
-	if ((test_bit(SOCK_PASSCRED, &sock->flags) ||
-	     test_bit(SOCK_PASSPIDFD, &sock->flags)) &&
-	    !READ_ONCE(u->addr)) {
+	if (unix_may_passcred(sk) && !READ_ONCE(u->addr)) {
 		err = unix_autobind(sk);
 		if (err)
 			goto out;
@@ -1877,16 +1881,6 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
 	return err;
 }
 
-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_PASSPIDFD, &other->sk_socket->flags);
-}
-
 /*
  * Some apps rely on write() giving SCM_CREDENTIALS
  * We include credentials if source or destination socket
@@ -1897,7 +1891,9 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
 {
 	if (UNIXCB(skb).pid)
 		return;
-	if (unix_passcred_enabled(sock, other)) {
+
+	if (unix_may_passcred(sock->sk) ||
+	    !other->sk_socket || unix_may_passcred(other)) {
 		UNIXCB(skb).pid  = get_pid(task_tgid(current));
 		current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
 	}
@@ -1974,9 +1970,7 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 			goto out;
 	}
 
-	if ((test_bit(SOCK_PASSCRED, &sock->flags) ||
-	     test_bit(SOCK_PASSPIDFD, &sock->flags)) &&
-	    !READ_ONCE(u->addr)) {
+	if (unix_may_passcred(sk) && !READ_ONCE(u->addr)) {
 		err = unix_autobind(sk);
 		if (err)
 			goto out;
@@ -2846,8 +2840,7 @@ 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) ||
-			   test_bit(SOCK_PASSPIDFD, &sock->flags)) {
+		} else if (unix_may_passcred(sk)) {
 			/* Copy credentials */
 			scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
 			unix_set_secdata(&scm, skb);
-- 
2.49.0


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

* [PATCH v5 net-next 2/9] af_unix: Don't pass struct socket to maybe_add_creds().
  2025-05-19 20:57 [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
  2025-05-19 20:57 ` [PATCH v5 net-next 1/9] af_unix: Factorise test_bit() for SOCK_PASSCRED and SOCK_PASSPIDFD Kuniyuki Iwashima
@ 2025-05-19 20:57 ` Kuniyuki Iwashima
  2025-05-19 20:57 ` [PATCH v5 net-next 3/9] scm: Move scm_recv() from scm.h to scm.c Kuniyuki Iwashima
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Kuniyuki Iwashima @ 2025-05-19 20:57 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima,
	Kuniyuki Iwashima, netdev

We will move SOCK_PASS{CRED,PIDFD,SEC} from struct socket.flags
to struct sock for better handling with SOCK_PASSRIGHTS.

Then, we don't need to access struct socket in maybe_add_creds().

Let's pass struct sock to maybe_add_creds() and its caller
queue_oob().

While at it, we append the unix_ prefix and fix double spaces
around the pid assignment.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
 net/unix/af_unix.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 464e183ffdb8..a39497fd6e98 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1869,7 +1869,7 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
 {
 	int err = 0;
 
-	UNIXCB(skb).pid  = get_pid(scm->pid);
+	UNIXCB(skb).pid = get_pid(scm->pid);
 	UNIXCB(skb).uid = scm->creds.uid;
 	UNIXCB(skb).gid = scm->creds.gid;
 	UNIXCB(skb).fp = NULL;
@@ -1886,15 +1886,15 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
  * We include credentials if source or destination socket
  * asserted SOCK_PASSCRED.
  */
-static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
-			    const struct sock *other)
+static void unix_maybe_add_creds(struct sk_buff *skb, const struct sock *sk,
+				 const struct sock *other)
 {
 	if (UNIXCB(skb).pid)
 		return;
 
-	if (unix_may_passcred(sock->sk) ||
+	if (unix_may_passcred(sk) ||
 	    !other->sk_socket || unix_may_passcred(other)) {
-		UNIXCB(skb).pid  = get_pid(task_tgid(current));
+		UNIXCB(skb).pid = get_pid(task_tgid(current));
 		current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
 	}
 }
@@ -2133,7 +2133,8 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 
 	if (sock_flag(other, SOCK_RCVTSTAMP))
 		__net_timestamp(skb);
-	maybe_add_creds(skb, sock, other);
+
+	unix_maybe_add_creds(skb, sk, other);
 	scm_stat_add(other, skb);
 	skb_queue_tail(&other->sk_receive_queue, skb);
 	unix_state_unlock(other);
@@ -2161,14 +2162,14 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 #define UNIX_SKB_FRAGS_SZ (PAGE_SIZE << get_order(32768))
 
 #if IS_ENABLED(CONFIG_AF_UNIX_OOB)
-static int queue_oob(struct socket *sock, struct msghdr *msg, struct sock *other,
+static int queue_oob(struct sock *sk, struct msghdr *msg, struct sock *other,
 		     struct scm_cookie *scm, bool fds_sent)
 {
 	struct unix_sock *ousk = unix_sk(other);
 	struct sk_buff *skb;
 	int err;
 
-	skb = sock_alloc_send_skb(sock->sk, 1, msg->msg_flags & MSG_DONTWAIT, &err);
+	skb = sock_alloc_send_skb(sk, 1, msg->msg_flags & MSG_DONTWAIT, &err);
 
 	if (!skb)
 		return err;
@@ -2192,7 +2193,7 @@ static int queue_oob(struct socket *sock, struct msghdr *msg, struct sock *other
 		goto out;
 	}
 
-	maybe_add_creds(skb, sock, other);
+	unix_maybe_add_creds(skb, sk, other);
 	scm_stat_add(other, skb);
 
 	spin_lock(&other->sk_receive_queue.lock);
@@ -2308,7 +2309,7 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
 		    (other->sk_shutdown & RCV_SHUTDOWN))
 			goto out_pipe_unlock;
 
-		maybe_add_creds(skb, sock, other);
+		unix_maybe_add_creds(skb, sk, other);
 		scm_stat_add(other, skb);
 		skb_queue_tail(&other->sk_receive_queue, skb);
 		unix_state_unlock(other);
@@ -2318,7 +2319,7 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
 
 #if IS_ENABLED(CONFIG_AF_UNIX_OOB)
 	if (msg->msg_flags & MSG_OOB) {
-		err = queue_oob(sock, msg, other, &scm, fds_sent);
+		err = queue_oob(sk, msg, other, &scm, fds_sent);
 		if (err)
 			goto out_err;
 		sent++;
-- 
2.49.0


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

* [PATCH v5 net-next 3/9] scm: Move scm_recv() from scm.h to scm.c.
  2025-05-19 20:57 [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
  2025-05-19 20:57 ` [PATCH v5 net-next 1/9] af_unix: Factorise test_bit() for SOCK_PASSCRED and SOCK_PASSPIDFD Kuniyuki Iwashima
  2025-05-19 20:57 ` [PATCH v5 net-next 2/9] af_unix: Don't pass struct socket to maybe_add_creds() Kuniyuki Iwashima
@ 2025-05-19 20:57 ` Kuniyuki Iwashima
  2025-05-19 20:57 ` [PATCH v5 net-next 4/9] tcp: Restrict SO_TXREHASH to TCP socket Kuniyuki Iwashima
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Kuniyuki Iwashima @ 2025-05-19 20:57 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima,
	Kuniyuki Iwashima, netdev

scm_recv() has been placed in scm.h since the pre-git era for no
particular reason (I think), which makes the file really fragile.

For example, when you move SOCK_PASSCRED from include/linux/net.h to
enum sock_flags in include/net/sock.h, you will see weird build failure
due to terrible dependency.

To avoid the build failure in the future, let's move scm_recv(_unix())?
and its callees to scm.c.

Note that only scm_recv() needs to be exported for Bluetooth.

scm_send() should be moved to scm.c too, but I'll revisit later.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
v3: Remove inline in scm.c
---
 include/net/scm.h | 121 ++-------------------------------------------
 net/core/scm.c    | 123 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 127 insertions(+), 117 deletions(-)

diff --git a/include/net/scm.h b/include/net/scm.h
index 22bb49589fde..84c4707e78a5 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -102,123 +102,10 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
 	return __scm_send(sock, msg, scm);
 }
 
-#ifdef CONFIG_SECURITY_NETWORK
-static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
-{
-	struct lsm_context ctx;
-	int err;
-
-	if (test_bit(SOCK_PASSSEC, &sock->flags)) {
-		err = security_secid_to_secctx(scm->secid, &ctx);
-
-		if (err >= 0) {
-			put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, ctx.len,
-				 ctx.context);
-			security_release_secctx(&ctx);
-		}
-	}
-}
-
-static inline bool scm_has_secdata(struct socket *sock)
-{
-	return test_bit(SOCK_PASSSEC, &sock->flags);
-}
-#else
-static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
-{ }
-
-static inline bool scm_has_secdata(struct socket *sock)
-{
-	return false;
-}
-#endif /* CONFIG_SECURITY_NETWORK */
-
-static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm)
-{
-	struct file *pidfd_file = NULL;
-	int len, 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_flags & MSG_CMSG_COMPAT)
-		len = sizeof(struct compat_cmsghdr) + sizeof(int);
-	else
-		len = sizeof(struct cmsghdr) + sizeof(int);
-
-	if (msg->msg_controllen < len) {
-		msg->msg_flags |= MSG_CTRUNC;
-		return;
-	}
-
-	if (!scm->pid)
-		return;
-
-	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 bool __scm_recv_common(struct socket *sock, struct msghdr *msg,
-				     struct scm_cookie *scm, int flags)
-{
-	if (!msg->msg_control) {
-		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 false;
-	}
-
-	if (test_bit(SOCK_PASSCRED, &sock->flags)) {
-		struct user_namespace *current_ns = current_user_ns();
-		struct ucred ucreds = {
-			.pid = scm->creds.pid,
-			.uid = from_kuid_munged(current_ns, scm->creds.uid),
-			.gid = from_kgid_munged(current_ns, scm->creds.gid),
-		};
-		put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
-	}
-
-	scm_passec(sock, msg, scm);
-
-	if (scm->fp)
-		scm_detach_fds(msg, scm);
-
-	return true;
-}
-
-static inline void scm_recv(struct socket *sock, struct msghdr *msg,
-			    struct scm_cookie *scm, int flags)
-{
-	if (!__scm_recv_common(sock, msg, scm, flags))
-		return;
-
-	scm_destroy_cred(scm);
-}
-
-static inline void scm_recv_unix(struct socket *sock, struct msghdr *msg,
-				 struct scm_cookie *scm, int flags)
-{
-	if (!__scm_recv_common(sock, msg, scm, flags))
-		return;
-
-	if (test_bit(SOCK_PASSPIDFD, &sock->flags))
-		scm_pidfd_recv(msg, scm);
-
-	scm_destroy_cred(scm);
-}
+void scm_recv(struct socket *sock, struct msghdr *msg,
+	      struct scm_cookie *scm, int flags);
+void scm_recv_unix(struct socket *sock, struct msghdr *msg,
+		   struct scm_cookie *scm, int flags);
 
 static inline int scm_recv_one_fd(struct file *f, int __user *ufd,
 				  unsigned int flags)
diff --git a/net/core/scm.c b/net/core/scm.c
index 733c0cbd393d..66e02b18c359 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -404,3 +404,126 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
 	return new_fpl;
 }
 EXPORT_SYMBOL(scm_fp_dup);
+
+#ifdef CONFIG_SECURITY_NETWORK
+static void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
+{
+	struct lsm_context ctx;
+	int err;
+
+	if (test_bit(SOCK_PASSSEC, &sock->flags)) {
+		err = security_secid_to_secctx(scm->secid, &ctx);
+
+		if (err >= 0) {
+			put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, ctx.len,
+				 ctx.context);
+
+			security_release_secctx(&ctx);
+		}
+	}
+}
+
+static bool scm_has_secdata(struct socket *sock)
+{
+	return test_bit(SOCK_PASSSEC, &sock->flags);
+}
+#else
+static void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
+{
+}
+
+static bool scm_has_secdata(struct socket *sock)
+{
+	return false;
+}
+#endif
+
+static void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm)
+{
+	struct file *pidfd_file = NULL;
+	int len, 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_flags & MSG_CMSG_COMPAT)
+		len = sizeof(struct compat_cmsghdr) + sizeof(int);
+	else
+		len = sizeof(struct cmsghdr) + sizeof(int);
+
+	if (msg->msg_controllen < len) {
+		msg->msg_flags |= MSG_CTRUNC;
+		return;
+	}
+
+	if (!scm->pid)
+		return;
+
+	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 bool __scm_recv_common(struct socket *sock, struct msghdr *msg,
+			      struct scm_cookie *scm, int flags)
+{
+	if (!msg->msg_control) {
+		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 false;
+	}
+
+	if (test_bit(SOCK_PASSCRED, &sock->flags)) {
+		struct user_namespace *current_ns = current_user_ns();
+		struct ucred ucreds = {
+			.pid = scm->creds.pid,
+			.uid = from_kuid_munged(current_ns, scm->creds.uid),
+			.gid = from_kgid_munged(current_ns, scm->creds.gid),
+		};
+
+		put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
+	}
+
+	scm_passec(sock, msg, scm);
+
+	if (scm->fp)
+		scm_detach_fds(msg, scm);
+
+	return true;
+}
+
+void scm_recv(struct socket *sock, struct msghdr *msg,
+	      struct scm_cookie *scm, int flags)
+{
+	if (!__scm_recv_common(sock, msg, scm, flags))
+		return;
+
+	scm_destroy_cred(scm);
+}
+EXPORT_SYMBOL(scm_recv);
+
+void scm_recv_unix(struct socket *sock, struct msghdr *msg,
+		   struct scm_cookie *scm, int flags)
+{
+	if (!__scm_recv_common(sock, msg, scm, flags))
+		return;
+
+	if (test_bit(SOCK_PASSPIDFD, &sock->flags))
+		scm_pidfd_recv(msg, scm);
+
+	scm_destroy_cred(scm);
+}
-- 
2.49.0


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

* [PATCH v5 net-next 4/9] tcp: Restrict SO_TXREHASH to TCP socket.
  2025-05-19 20:57 [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
                   ` (2 preceding siblings ...)
  2025-05-19 20:57 ` [PATCH v5 net-next 3/9] scm: Move scm_recv() from scm.h to scm.c Kuniyuki Iwashima
@ 2025-05-19 20:57 ` Kuniyuki Iwashima
  2025-05-19 20:57 ` [PATCH v5 net-next 5/9] net: Restrict SO_PASS{CRED,PIDFD,SEC} to AF_{UNIX,NETLINK,BLUETOOTH} Kuniyuki Iwashima
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Kuniyuki Iwashima @ 2025-05-19 20:57 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima,
	Kuniyuki Iwashima, netdev

sk->sk_txrehash is only used for TCP.

Let's restrict SO_TXREHASH to TCP to reflect this.

Later, we will make sk_txrehash a part of the union for other
protocol families.

Note that we need to modify BPF selftest not to get/set
SO_TEREHASH for non-TCP sockets.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
v5: Modify BPF selftest not to set SO_TEREHASH for UDP socket
v3: Return -EOPNOTSUPP for getsockopt() too
---
 net/core/sock.c                                    |  5 +++++
 tools/testing/selftests/bpf/progs/setget_sockopt.c | 11 +++++++++++
 2 files changed, 16 insertions(+)

diff --git a/net/core/sock.c b/net/core/sock.c
index 347ce75482f5..d7d6d3a8efe5 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1276,6 +1276,8 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
 		return 0;
 		}
 	case SO_TXREHASH:
+		if (!sk_is_tcp(sk))
+			return -EOPNOTSUPP;
 		if (val < -1 || val > 1)
 			return -EINVAL;
 		if ((u8)val == SOCK_TXREHASH_DEFAULT)
@@ -2102,6 +2104,9 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
 		break;
 
 	case SO_TXREHASH:
+		if (!sk_is_tcp(sk))
+			return -EOPNOTSUPP;
+
 		/* Paired with WRITE_ONCE() in sk_setsockopt() */
 		v.val = READ_ONCE(sk->sk_txrehash);
 		break;
diff --git a/tools/testing/selftests/bpf/progs/setget_sockopt.c b/tools/testing/selftests/bpf/progs/setget_sockopt.c
index 0107a24b7522..d330b1511979 100644
--- a/tools/testing/selftests/bpf/progs/setget_sockopt.c
+++ b/tools/testing/selftests/bpf/progs/setget_sockopt.c
@@ -83,6 +83,14 @@ struct loop_ctx {
 	struct sock *sk;
 };
 
+static bool sk_is_tcp(struct sock *sk)
+{
+	return (sk->__sk_common.skc_family == AF_INET ||
+		sk->__sk_common.skc_family == AF_INET6) &&
+		sk->sk_type == SOCK_STREAM &&
+		sk->sk_protocol == IPPROTO_TCP;
+}
+
 static int bpf_test_sockopt_flip(void *ctx, struct sock *sk,
 				 const struct sockopt_test *t,
 				 int level)
@@ -91,6 +99,9 @@ static int bpf_test_sockopt_flip(void *ctx, struct sock *sk,
 
 	opt = t->opt;
 
+	if (opt == SO_TXREHASH && !sk_is_tcp(sk))
+		return 0;
+
 	if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old)))
 		return 1;
 	/* kernel initialized txrehash to 255 */
-- 
2.49.0


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

* [PATCH v5 net-next 5/9] net: Restrict SO_PASS{CRED,PIDFD,SEC} to AF_{UNIX,NETLINK,BLUETOOTH}.
  2025-05-19 20:57 [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
                   ` (3 preceding siblings ...)
  2025-05-19 20:57 ` [PATCH v5 net-next 4/9] tcp: Restrict SO_TXREHASH to TCP socket Kuniyuki Iwashima
@ 2025-05-19 20:57 ` Kuniyuki Iwashima
  2025-06-09 11:14   ` Luca Boccassi
  2025-05-19 20:57 ` [PATCH v5 net-next 6/9] af_unix: Move SOCK_PASS{CRED,PIDFD,SEC} to struct sock Kuniyuki Iwashima
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 15+ messages in thread
From: Kuniyuki Iwashima @ 2025-05-19 20:57 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima,
	Kuniyuki Iwashima, netdev

SCM_CREDENTIALS and SCM_SECURITY can be recv()ed by calling
scm_recv() or scm_recv_unix(), and SCM_PIDFD is only used by
scm_recv_unix().

scm_recv() is called from AF_NETLINK and AF_BLUETOOTH.

scm_recv_unix() is literally called from AF_UNIX.

Let's restrict SO_PASSCRED and SO_PASSSEC to such sockets and
SO_PASSPIDFD to AF_UNIX only.

Later, SOCK_PASS{CRED,PIDFD,SEC} will be moved to struct sock
and united with another field.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
v3:
  * Return -EOPNOTSUPP in getsockopt() too
  * Add CONFIG_SECURITY_NETWORK check for SO_PASSSEC
---
 include/net/sock.h | 14 +++++++++++++-
 net/core/sock.c    | 18 ++++++++++++++++++
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/include/net/sock.h b/include/net/sock.h
index 3e15d7105ad2..56fa558d24c0 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2773,9 +2773,14 @@ static inline bool sk_is_udp(const struct sock *sk)
 	       sk->sk_protocol == IPPROTO_UDP;
 }
 
+static inline bool sk_is_unix(const struct sock *sk)
+{
+	return sk->sk_family == AF_UNIX;
+}
+
 static inline bool sk_is_stream_unix(const struct sock *sk)
 {
-	return sk->sk_family == AF_UNIX && sk->sk_type == SOCK_STREAM;
+	return sk_is_unix(sk) && sk->sk_type == SOCK_STREAM;
 }
 
 static inline bool sk_is_vsock(const struct sock *sk)
@@ -2783,6 +2788,13 @@ static inline bool sk_is_vsock(const struct sock *sk)
 	return sk->sk_family == AF_VSOCK;
 }
 
+static inline bool sk_may_scm_recv(const struct sock *sk)
+{
+	return (IS_ENABLED(CONFIG_UNIX) && sk->sk_family == AF_UNIX) ||
+		sk->sk_family == AF_NETLINK ||
+		(IS_ENABLED(CONFIG_BT) && sk->sk_family == AF_BLUETOOTH);
+}
+
 /**
  * sk_eat_skb - Release a skb if it is no longer needed
  * @sk: socket to eat this skb from
diff --git a/net/core/sock.c b/net/core/sock.c
index d7d6d3a8efe5..fd5f9d3873c1 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1221,12 +1221,21 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
 		}
 		return -EPERM;
 	case SO_PASSSEC:
+		if (!IS_ENABLED(CONFIG_SECURITY_NETWORK) || sk_may_scm_recv(sk))
+			return -EOPNOTSUPP;
+
 		assign_bit(SOCK_PASSSEC, &sock->flags, valbool);
 		return 0;
 	case SO_PASSCRED:
+		if (!sk_may_scm_recv(sk))
+			return -EOPNOTSUPP;
+
 		assign_bit(SOCK_PASSCRED, &sock->flags, valbool);
 		return 0;
 	case SO_PASSPIDFD:
+		if (!sk_is_unix(sk))
+			return -EOPNOTSUPP;
+
 		assign_bit(SOCK_PASSPIDFD, &sock->flags, valbool);
 		return 0;
 	case SO_TYPE:
@@ -1855,10 +1864,16 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
 		break;
 
 	case SO_PASSCRED:
+		if (!sk_may_scm_recv(sk))
+			return -EOPNOTSUPP;
+
 		v.val = !!test_bit(SOCK_PASSCRED, &sock->flags);
 		break;
 
 	case SO_PASSPIDFD:
+		if (!sk_is_unix(sk))
+			return -EOPNOTSUPP;
+
 		v.val = !!test_bit(SOCK_PASSPIDFD, &sock->flags);
 		break;
 
@@ -1956,6 +1971,9 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
 		break;
 
 	case SO_PASSSEC:
+		if (!IS_ENABLED(CONFIG_SECURITY_NETWORK) || !sk_may_scm_recv(sk))
+			return -EOPNOTSUPP;
+
 		v.val = !!test_bit(SOCK_PASSSEC, &sock->flags);
 		break;
 
-- 
2.49.0


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

* [PATCH v5 net-next 6/9] af_unix: Move SOCK_PASS{CRED,PIDFD,SEC} to struct sock.
  2025-05-19 20:57 [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
                   ` (4 preceding siblings ...)
  2025-05-19 20:57 ` [PATCH v5 net-next 5/9] net: Restrict SO_PASS{CRED,PIDFD,SEC} to AF_{UNIX,NETLINK,BLUETOOTH} Kuniyuki Iwashima
@ 2025-05-19 20:57 ` Kuniyuki Iwashima
  2025-05-19 20:57 ` [PATCH v5 net-next 7/9] af_unix: Inherit sk_flags at connect() Kuniyuki Iwashima
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Kuniyuki Iwashima @ 2025-05-19 20:57 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima,
	Kuniyuki Iwashima, netdev

As explained in the next patch, SO_PASSRIGHTS would have a problem
if we assigned a corresponding bit to socket->flags, so it must be
managed in struct sock.

Mixing socket->flags and sk->sk_flags for similar options will look
confusing, and sk->sk_flags does not have enough space on 32bit system.

Also, as mentioned in commit 16e572626961 ("af_unix: dont send
SCM_CREDENTIALS by default"), SOCK_PASSCRED and SOCK_PASSPID handling
is known to be slow, and managing the flags in struct socket cannot
avoid that for embryo sockets.

Let's move SOCK_PASS{CRED,PIDFD,SEC} to struct sock.

While at it, other SOCK_XXX flags in net.h are grouped as enum.

Note that assign_bit() was atomic, so the writer side is moved down
after lock_sock() in setsockopt(), but the bit is only read once
in sendmsg() and recvmsg(), so lock_sock() is not needed there.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
v4:
  * Group sk->sk_scm_XXX bits by struct

v3:
  * Add kdoc for sk_scm_unused
  * Update sk->sk_scm_xxx after lock_sock() in setsockopt()
---
 include/linux/net.h | 15 +++++++--------
 include/net/sock.h  | 16 +++++++++++++++-
 net/core/scm.c      | 29 ++++++++++++++---------------
 net/core/sock.c     | 44 +++++++++++++++++++++++---------------------
 net/unix/af_unix.c  | 18 ++----------------
 5 files changed, 61 insertions(+), 61 deletions(-)

diff --git a/include/linux/net.h b/include/linux/net.h
index 0ff950eecc6b..f8418d6e33e0 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -36,14 +36,13 @@ struct net;
  * in sock->flags, but moved into sk->sk_wq->flags to be RCU protected.
  * Eventually all flags will be in sk->sk_wq->flags.
  */
-#define SOCKWQ_ASYNC_NOSPACE	0
-#define SOCKWQ_ASYNC_WAITDATA	1
-#define SOCK_NOSPACE		2
-#define SOCK_PASSCRED		3
-#define SOCK_PASSSEC		4
-#define SOCK_SUPPORT_ZC		5
-#define SOCK_CUSTOM_SOCKOPT	6
-#define SOCK_PASSPIDFD		7
+enum socket_flags {
+	SOCKWQ_ASYNC_NOSPACE,
+	SOCKWQ_ASYNC_WAITDATA,
+	SOCK_NOSPACE,
+	SOCK_SUPPORT_ZC,
+	SOCK_CUSTOM_SOCKOPT,
+};
 
 #ifndef ARCH_HAS_SOCKET_TYPES
 /**
diff --git a/include/net/sock.h b/include/net/sock.h
index 56fa558d24c0..d14d7d960d44 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -337,6 +337,11 @@ struct sk_filter;
   *	@sk_txtime_deadline_mode: set deadline mode for SO_TXTIME
   *	@sk_txtime_report_errors: set report errors mode for SO_TXTIME
   *	@sk_txtime_unused: unused txtime flags
+  *	@sk_scm_recv_flags: all flags used by scm_recv()
+  *	@sk_scm_credentials: flagged by SO_PASSCRED to recv SCM_CREDENTIALS
+  *	@sk_scm_security: flagged by SO_PASSSEC to recv SCM_SECURITY
+  *	@sk_scm_pidfd: flagged by SO_PASSPIDFD to recv SCM_PIDFD
+  *	@sk_scm_unused: unused flags for scm_recv()
   *	@ns_tracker: tracker for netns reference
   *	@sk_user_frags: xarray of pages the user is holding a reference on.
   *	@sk_owner: reference to the real owner of the socket that calls
@@ -523,7 +528,16 @@ struct sock {
 #endif
 	int			sk_disconnects;
 
-	u8			sk_txrehash;
+	union {
+		u8		sk_txrehash;
+		u8		sk_scm_recv_flags;
+		struct {
+			u8	sk_scm_credentials : 1,
+				sk_scm_security : 1,
+				sk_scm_pidfd : 1,
+				sk_scm_unused : 5;
+		};
+	};
 	u8			sk_clockid;
 	u8			sk_txtime_deadline_mode : 1,
 				sk_txtime_report_errors : 1,
diff --git a/net/core/scm.c b/net/core/scm.c
index 66e02b18c359..0225bd94170f 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -406,12 +406,12 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
 EXPORT_SYMBOL(scm_fp_dup);
 
 #ifdef CONFIG_SECURITY_NETWORK
-static void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
+static void scm_passec(struct sock *sk, struct msghdr *msg, struct scm_cookie *scm)
 {
 	struct lsm_context ctx;
 	int err;
 
-	if (test_bit(SOCK_PASSSEC, &sock->flags)) {
+	if (sk->sk_scm_security) {
 		err = security_secid_to_secctx(scm->secid, &ctx);
 
 		if (err >= 0) {
@@ -423,16 +423,16 @@ static void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cooki
 	}
 }
 
-static bool scm_has_secdata(struct socket *sock)
+static bool scm_has_secdata(struct sock *sk)
 {
-	return test_bit(SOCK_PASSSEC, &sock->flags);
+	return sk->sk_scm_security;
 }
 #else
-static void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
+static void scm_passec(struct sock *sk, struct msghdr *msg, struct scm_cookie *scm)
 {
 }
 
-static bool scm_has_secdata(struct socket *sock)
+static bool scm_has_secdata(struct sock *sk)
 {
 	return false;
 }
@@ -474,20 +474,19 @@ static void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm)
 		fd_install(pidfd, pidfd_file);
 }
 
-static bool __scm_recv_common(struct socket *sock, struct msghdr *msg,
+static bool __scm_recv_common(struct sock *sk, struct msghdr *msg,
 			      struct scm_cookie *scm, int flags)
 {
 	if (!msg->msg_control) {
-		if (test_bit(SOCK_PASSCRED, &sock->flags) ||
-		    test_bit(SOCK_PASSPIDFD, &sock->flags) ||
-		    scm->fp || scm_has_secdata(sock))
+		if (sk->sk_scm_credentials || sk->sk_scm_pidfd ||
+		    scm->fp || scm_has_secdata(sk))
 			msg->msg_flags |= MSG_CTRUNC;
 
 		scm_destroy(scm);
 		return false;
 	}
 
-	if (test_bit(SOCK_PASSCRED, &sock->flags)) {
+	if (sk->sk_scm_credentials) {
 		struct user_namespace *current_ns = current_user_ns();
 		struct ucred ucreds = {
 			.pid = scm->creds.pid,
@@ -498,7 +497,7 @@ static bool __scm_recv_common(struct socket *sock, struct msghdr *msg,
 		put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
 	}
 
-	scm_passec(sock, msg, scm);
+	scm_passec(sk, msg, scm);
 
 	if (scm->fp)
 		scm_detach_fds(msg, scm);
@@ -509,7 +508,7 @@ static bool __scm_recv_common(struct socket *sock, struct msghdr *msg,
 void scm_recv(struct socket *sock, struct msghdr *msg,
 	      struct scm_cookie *scm, int flags)
 {
-	if (!__scm_recv_common(sock, msg, scm, flags))
+	if (!__scm_recv_common(sock->sk, msg, scm, flags))
 		return;
 
 	scm_destroy_cred(scm);
@@ -519,10 +518,10 @@ EXPORT_SYMBOL(scm_recv);
 void scm_recv_unix(struct socket *sock, struct msghdr *msg,
 		   struct scm_cookie *scm, int flags)
 {
-	if (!__scm_recv_common(sock, msg, scm, flags))
+	if (!__scm_recv_common(sock->sk, msg, scm, flags))
 		return;
 
-	if (test_bit(SOCK_PASSPIDFD, &sock->flags))
+	if (sock->sk->sk_scm_pidfd)
 		scm_pidfd_recv(msg, scm);
 
 	scm_destroy_cred(scm);
diff --git a/net/core/sock.c b/net/core/sock.c
index fd5f9d3873c1..381abf8f25b7 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1220,24 +1220,6 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
 			return 0;
 		}
 		return -EPERM;
-	case SO_PASSSEC:
-		if (!IS_ENABLED(CONFIG_SECURITY_NETWORK) || sk_may_scm_recv(sk))
-			return -EOPNOTSUPP;
-
-		assign_bit(SOCK_PASSSEC, &sock->flags, valbool);
-		return 0;
-	case SO_PASSCRED:
-		if (!sk_may_scm_recv(sk))
-			return -EOPNOTSUPP;
-
-		assign_bit(SOCK_PASSCRED, &sock->flags, valbool);
-		return 0;
-	case SO_PASSPIDFD:
-		if (!sk_is_unix(sk))
-			return -EOPNOTSUPP;
-
-		assign_bit(SOCK_PASSPIDFD, &sock->flags, valbool);
-		return 0;
 	case SO_TYPE:
 	case SO_PROTOCOL:
 	case SO_DOMAIN:
@@ -1568,6 +1550,26 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
 		sock_valbool_flag(sk, SOCK_SELECT_ERR_QUEUE, valbool);
 		break;
 
+	case SO_PASSCRED:
+		if (sk_may_scm_recv(sk))
+			sk->sk_scm_credentials = valbool;
+		else
+			ret = -EOPNOTSUPP;
+		break;
+
+	case SO_PASSSEC:
+		if (IS_ENABLED(CONFIG_SECURITY_NETWORK) && sk_may_scm_recv(sk))
+			sk->sk_scm_security = valbool;
+		else
+			ret = -EOPNOTSUPP;
+		break;
+
+	case SO_PASSPIDFD:
+		if (sk_is_unix(sk))
+			sk->sk_scm_pidfd = valbool;
+		else
+			ret = -EOPNOTSUPP;
+		break;
 
 	case SO_INCOMING_CPU:
 		reuseport_update_incoming_cpu(sk, val);
@@ -1867,14 +1869,14 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
 		if (!sk_may_scm_recv(sk))
 			return -EOPNOTSUPP;
 
-		v.val = !!test_bit(SOCK_PASSCRED, &sock->flags);
+		v.val = sk->sk_scm_credentials;
 		break;
 
 	case SO_PASSPIDFD:
 		if (!sk_is_unix(sk))
 			return -EOPNOTSUPP;
 
-		v.val = !!test_bit(SOCK_PASSPIDFD, &sock->flags);
+		v.val = sk->sk_scm_pidfd;
 		break;
 
 	case SO_PEERCRED:
@@ -1974,7 +1976,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
 		if (!IS_ENABLED(CONFIG_SECURITY_NETWORK) || !sk_may_scm_recv(sk))
 			return -EOPNOTSUPP;
 
-		v.val = !!test_bit(SOCK_PASSSEC, &sock->flags);
+		v.val = sk->sk_scm_security;
 		break;
 
 	case SO_PEERSEC:
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index a39497fd6e98..27ebda4cd9b9 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -767,10 +767,7 @@ static void copy_peercred(struct sock *sk, struct sock *peersk)
 
 static bool unix_may_passcred(const struct sock *sk)
 {
-	struct socket *sock = sk->sk_socket;
-
-	return test_bit(SOCK_PASSCRED, &sock->flags) ||
-		test_bit(SOCK_PASSPIDFD, &sock->flags);
+	return sk->sk_scm_credentials || sk->sk_scm_pidfd;
 }
 
 static int unix_listen(struct socket *sock, int backlog)
@@ -1713,17 +1710,6 @@ static int unix_socketpair(struct socket *socka, struct socket *sockb)
 	return 0;
 }
 
-static void unix_sock_inherit_flags(const struct socket *old,
-				    struct socket *new)
-{
-	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);
-}
-
 static int unix_accept(struct socket *sock, struct socket *newsock,
 		       struct proto_accept_arg *arg)
 {
@@ -1760,7 +1746,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock,
 	unix_state_lock(tsk);
 	unix_update_edges(unix_sk(tsk));
 	newsock->state = SS_CONNECTED;
-	unix_sock_inherit_flags(sock, newsock);
+	tsk->sk_scm_recv_flags = READ_ONCE(sk->sk_scm_recv_flags);
 	sock_graft(tsk, newsock);
 	unix_state_unlock(tsk);
 	return 0;
-- 
2.49.0


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

* [PATCH v5 net-next 7/9] af_unix: Inherit sk_flags at connect().
  2025-05-19 20:57 [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
                   ` (5 preceding siblings ...)
  2025-05-19 20:57 ` [PATCH v5 net-next 6/9] af_unix: Move SOCK_PASS{CRED,PIDFD,SEC} to struct sock Kuniyuki Iwashima
@ 2025-05-19 20:57 ` Kuniyuki Iwashima
  2025-05-19 20:57 ` [PATCH v5 net-next 8/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Kuniyuki Iwashima @ 2025-05-19 20:57 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima,
	Kuniyuki Iwashima, netdev

For SOCK_STREAM embryo sockets, the SO_PASS{CRED,PIDFD,SEC} options
are inherited from the parent listen()ing socket.

Currently, this inheritance happens at accept(), because these
attributes were stored in sk->sk_socket->flags and the struct socket
is not allocated until accept().

This leads to unintentional behaviour.

When a peer sends data to an embryo socket in the accept() queue,
unix_maybe_add_creds() embeds credentials into the skb, even if
neither the peer nor the listener has enabled these options.

If the option is enabled, the embryo socket receives the ancillary
data after accept().  If not, the data is silently discarded.

This conservative approach works for SO_PASS{CRED,PIDFD,SEC}, but
would not for SO_PASSRIGHTS; once an SCM_RIGHTS with a hung file
descriptor was sent, it'd be game over.

To avoid this, we will need to preserve SOCK_PASSRIGHTS even on embryo
sockets.

Commit aed6ecef55d7 ("af_unix: Save listener for embryo socket.")
made it possible to access the parent's flags in sendmsg() via
unix_sk(other)->listener->sk->sk_socket->flags, but this introduces
an unnecessary condition that is irrelevant for most sockets,
accept()ed sockets and clients.

Therefore, we moved SOCK_PASSXXX into struct sock.

Let’s inherit sk->sk_scm_recv_flags at connect() to avoid receiving
SCM_RIGHTS on embryo sockets created from a parent with SO_PASSRIGHTS=0.

Note that the parent socket is locked in connect() so we don't need
READ_ONCE() for sk_scm_recv_flags.

Now, we can remove !other->sk_socket check in unix_maybe_add_creds()
to avoid slow SOCK_PASS{CRED,PIDFD} handling for embryo sockets
created from a parent with SO_PASS{CRED,PIDFD}=0.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
 net/unix/af_unix.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 27ebda4cd9b9..900bad88fbd2 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1626,10 +1626,12 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 	/* The way is open! Fastly set all the necessary fields... */
 
 	sock_hold(sk);
-	unix_peer(newsk)	= sk;
-	newsk->sk_state		= TCP_ESTABLISHED;
-	newsk->sk_type		= sk->sk_type;
+	unix_peer(newsk) = sk;
+	newsk->sk_state = TCP_ESTABLISHED;
+	newsk->sk_type = sk->sk_type;
+	newsk->sk_scm_recv_flags = other->sk_scm_recv_flags;
 	init_peercred(newsk);
+
 	newu = unix_sk(newsk);
 	newu->listener = other;
 	RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq);
@@ -1746,7 +1748,6 @@ static int unix_accept(struct socket *sock, struct socket *newsock,
 	unix_state_lock(tsk);
 	unix_update_edges(unix_sk(tsk));
 	newsock->state = SS_CONNECTED;
-	tsk->sk_scm_recv_flags = READ_ONCE(sk->sk_scm_recv_flags);
 	sock_graft(tsk, newsock);
 	unix_state_unlock(tsk);
 	return 0;
@@ -1878,8 +1879,7 @@ static void unix_maybe_add_creds(struct sk_buff *skb, const struct sock *sk,
 	if (UNIXCB(skb).pid)
 		return;
 
-	if (unix_may_passcred(sk) ||
-	    !other->sk_socket || unix_may_passcred(other)) {
+	if (unix_may_passcred(sk) || unix_may_passcred(other)) {
 		UNIXCB(skb).pid = get_pid(task_tgid(current));
 		current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
 	}
-- 
2.49.0


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

* [PATCH v5 net-next 8/9] af_unix: Introduce SO_PASSRIGHTS.
  2025-05-19 20:57 [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
                   ` (6 preceding siblings ...)
  2025-05-19 20:57 ` [PATCH v5 net-next 7/9] af_unix: Inherit sk_flags at connect() Kuniyuki Iwashima
@ 2025-05-19 20:57 ` Kuniyuki Iwashima
  2025-05-19 20:58 ` [PATCH v5 net-next 9/9] selftest: af_unix: Test SO_PASSRIGHTS Kuniyuki Iwashima
  2025-05-28 11:40 ` [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Paolo Abeni
  9 siblings, 0 replies; 15+ messages in thread
From: Kuniyuki Iwashima @ 2025-05-19 20:57 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima,
	Kuniyuki Iwashima, netdev

As long as recvmsg() or recvmmsg() is used with cmsg, it is not
possible to avoid receiving file descriptors via SCM_RIGHTS.

This behaviour has occasionally been flagged as problematic, as
it can be (ab)used to trigger DoS during close(), for example, by
passing a FUSE-controlled fd or a hung NFS fd.

For instance, as noted on the uAPI Group page [0], an untrusted peer
could send a file descriptor pointing to a hung NFS mount and then
close it.  Once the receiver calls recvmsg() with msg_control, the
descriptor is automatically installed, and then the responsibility
for the final close() now falls on the receiver, which may result
in blocking the process for a long time.

Regarding this, systemd calls cmsg_close_all() [1] after each
recvmsg() to close() unwanted file descriptors sent via SCM_RIGHTS.

However, this cannot work around the issue at all, because the final
fput() may still occur on the receiver's side once sendmsg() with
SCM_RIGHTS succeeds.  Also, even filtering by LSM at recvmsg() does
not work for the same reason.

Thus, we need a better way to refuse SCM_RIGHTS at sendmsg().

Let's introduce SO_PASSRIGHTS to disable SCM_RIGHTS.

Note that this option is enabled by default for backward
compatibility.

Link: https://uapi-group.org/kernel-features/#disabling-reception-of-scm_rights-for-af_unix-sockets #[0]
Link: https://github.com/systemd/systemd/blob/v257.5/src/basic/fd-util.c#L612-L628 #[1]
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
v3: Return -EOPNOTSUPP for getsockopt()
---
 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/net/sock.h                      |  4 +++-
 include/uapi/asm-generic/socket.h       |  2 ++
 net/core/sock.c                         | 14 ++++++++++++++
 net/unix/af_unix.c                      | 22 ++++++++++++++++++++--
 tools/include/uapi/asm-generic/socket.h |  2 ++
 9 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
index 3df5f2dd4c0f..8f1f18adcdb5 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -150,6 +150,8 @@
 
 #define SO_RCVPRIORITY		82
 
+#define SO_PASSRIGHTS		83
+
 #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 22fa8f19924a..31ac655b7837 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -161,6 +161,8 @@
 
 #define SO_RCVPRIORITY		82
 
+#define SO_PASSRIGHTS		83
+
 #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 96831c988606..1f2d5b7a7f5d 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -142,6 +142,8 @@
 #define SCM_DEVMEM_DMABUF	SO_DEVMEM_DMABUF
 #define SO_DEVMEM_DONTNEED	0x4050
 
+#define SO_PASSRIGHTS		0x4051
+
 #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 5b464a568664..adcba7329386 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -143,6 +143,8 @@
 
 #define SO_RCVPRIORITY           0x005b
 
+#define SO_PASSRIGHTS            0x005c
+
 #if !defined(__KERNEL__)
 
 
diff --git a/include/net/sock.h b/include/net/sock.h
index d14d7d960d44..1db4f40f2ecf 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -341,6 +341,7 @@ struct sk_filter;
   *	@sk_scm_credentials: flagged by SO_PASSCRED to recv SCM_CREDENTIALS
   *	@sk_scm_security: flagged by SO_PASSSEC to recv SCM_SECURITY
   *	@sk_scm_pidfd: flagged by SO_PASSPIDFD to recv SCM_PIDFD
+  *	@sk_scm_rights: flagged by SO_PASSRIGHTS to recv SCM_RIGHTS
   *	@sk_scm_unused: unused flags for scm_recv()
   *	@ns_tracker: tracker for netns reference
   *	@sk_user_frags: xarray of pages the user is holding a reference on.
@@ -535,7 +536,8 @@ struct sock {
 			u8	sk_scm_credentials : 1,
 				sk_scm_security : 1,
 				sk_scm_pidfd : 1,
-				sk_scm_unused : 5;
+				sk_scm_rights : 1,
+				sk_scm_unused : 4;
 		};
 	};
 	u8			sk_clockid;
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index aa5016ff3d91..f333a0ac4ee4 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -145,6 +145,8 @@
 
 #define SO_RCVPRIORITY		82
 
+#define SO_PASSRIGHTS		83
+
 #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 381abf8f25b7..0cb52e590094 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1571,6 +1571,13 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
 			ret = -EOPNOTSUPP;
 		break;
 
+	case SO_PASSRIGHTS:
+		if (sk_is_unix(sk))
+			sk->sk_scm_rights = valbool;
+		else
+			ret = -EOPNOTSUPP;
+		break;
+
 	case SO_INCOMING_CPU:
 		reuseport_update_incoming_cpu(sk, val);
 		break;
@@ -1879,6 +1886,13 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
 		v.val = sk->sk_scm_pidfd;
 		break;
 
+	case SO_PASSRIGHTS:
+		if (!sk_is_unix(sk))
+			return -EOPNOTSUPP;
+
+		v.val = sk->sk_scm_rights;
+		break;
+
 	case SO_PEERCRED:
 	{
 		struct ucred peercred;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 900bad88fbd2..bd507f74e35e 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1015,6 +1015,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern,
 
 	sock_init_data(sock, sk);
 
+	sk->sk_scm_rights	= 1;
 	sk->sk_hash		= unix_unbound_hash(sk);
 	sk->sk_allocation	= GFP_KERNEL_ACCOUNT;
 	sk->sk_write_space	= unix_write_space;
@@ -2073,6 +2074,11 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 		goto out_unlock;
 	}
 
+	if (UNIXCB(skb).fp && !other->sk_scm_rights) {
+		err = -EPERM;
+		goto out_unlock;
+	}
+
 	if (sk->sk_type != SOCK_SEQPACKET) {
 		err = security_unix_may_send(sk->sk_socket, other->sk_socket);
 		if (err)
@@ -2174,9 +2180,13 @@ static int queue_oob(struct sock *sk, struct msghdr *msg, struct sock *other,
 
 	if (sock_flag(other, SOCK_DEAD) ||
 	    (other->sk_shutdown & RCV_SHUTDOWN)) {
-		unix_state_unlock(other);
 		err = -EPIPE;
-		goto out;
+		goto out_unlock;
+	}
+
+	if (UNIXCB(skb).fp && !other->sk_scm_rights) {
+		err = -EPERM;
+		goto out_unlock;
 	}
 
 	unix_maybe_add_creds(skb, sk, other);
@@ -2192,6 +2202,8 @@ static int queue_oob(struct sock *sk, struct msghdr *msg, struct sock *other,
 	other->sk_data_ready(other);
 
 	return 0;
+out_unlock:
+	unix_state_unlock(other);
 out:
 	consume_skb(skb);
 	return err;
@@ -2295,6 +2307,12 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
 		    (other->sk_shutdown & RCV_SHUTDOWN))
 			goto out_pipe_unlock;
 
+		if (UNIXCB(skb).fp && !other->sk_scm_rights) {
+			unix_state_unlock(other);
+			err = -EPERM;
+			goto out_free;
+		}
+
 		unix_maybe_add_creds(skb, sk, other);
 		scm_stat_add(other, skb);
 		skb_queue_tail(&other->sk_receive_queue, skb);
diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h
index aa5016ff3d91..f333a0ac4ee4 100644
--- a/tools/include/uapi/asm-generic/socket.h
+++ b/tools/include/uapi/asm-generic/socket.h
@@ -145,6 +145,8 @@
 
 #define SO_RCVPRIORITY		82
 
+#define SO_PASSRIGHTS		83
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__))
-- 
2.49.0


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

* [PATCH v5 net-next 9/9] selftest: af_unix: Test SO_PASSRIGHTS.
  2025-05-19 20:57 [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
                   ` (7 preceding siblings ...)
  2025-05-19 20:57 ` [PATCH v5 net-next 8/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
@ 2025-05-19 20:58 ` Kuniyuki Iwashima
  2025-05-28 11:40 ` [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Paolo Abeni
  9 siblings, 0 replies; 15+ messages in thread
From: Kuniyuki Iwashima @ 2025-05-19 20:58 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima,
	Kuniyuki Iwashima, netdev

scm_rights.c has various patterns of tests to exercise GC.

Let's add cases where SO_PASSRIGHTS is disabled.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
v4: Removed errno juggling
---
 .../selftests/net/af_unix/scm_rights.c        | 80 ++++++++++++++++++-
 1 file changed, 78 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/net/af_unix/scm_rights.c b/tools/testing/selftests/net/af_unix/scm_rights.c
index d66336256580..8b015f16c03d 100644
--- a/tools/testing/selftests/net/af_unix/scm_rights.c
+++ b/tools/testing/selftests/net/af_unix/scm_rights.c
@@ -23,6 +23,7 @@ FIXTURE_VARIANT(scm_rights)
 	int type;
 	int flags;
 	bool test_listener;
+	bool disabled;
 };
 
 FIXTURE_VARIANT_ADD(scm_rights, dgram)
@@ -31,6 +32,16 @@ FIXTURE_VARIANT_ADD(scm_rights, dgram)
 	.type = SOCK_DGRAM,
 	.flags = 0,
 	.test_listener = false,
+	.disabled = false,
+};
+
+FIXTURE_VARIANT_ADD(scm_rights, dgram_disabled)
+{
+	.name = "UNIX ",
+	.type = SOCK_DGRAM,
+	.flags = 0,
+	.test_listener = false,
+	.disabled = true,
 };
 
 FIXTURE_VARIANT_ADD(scm_rights, stream)
@@ -39,6 +50,16 @@ FIXTURE_VARIANT_ADD(scm_rights, stream)
 	.type = SOCK_STREAM,
 	.flags = 0,
 	.test_listener = false,
+	.disabled = false,
+};
+
+FIXTURE_VARIANT_ADD(scm_rights, stream_disabled)
+{
+	.name = "UNIX-STREAM ",
+	.type = SOCK_STREAM,
+	.flags = 0,
+	.test_listener = false,
+	.disabled = true,
 };
 
 FIXTURE_VARIANT_ADD(scm_rights, stream_oob)
@@ -47,6 +68,16 @@ FIXTURE_VARIANT_ADD(scm_rights, stream_oob)
 	.type = SOCK_STREAM,
 	.flags = MSG_OOB,
 	.test_listener = false,
+	.disabled = false,
+};
+
+FIXTURE_VARIANT_ADD(scm_rights, stream_oob_disabled)
+{
+	.name = "UNIX-STREAM ",
+	.type = SOCK_STREAM,
+	.flags = MSG_OOB,
+	.test_listener = false,
+	.disabled = true,
 };
 
 FIXTURE_VARIANT_ADD(scm_rights, stream_listener)
@@ -55,6 +86,16 @@ FIXTURE_VARIANT_ADD(scm_rights, stream_listener)
 	.type = SOCK_STREAM,
 	.flags = 0,
 	.test_listener = true,
+	.disabled = false,
+};
+
+FIXTURE_VARIANT_ADD(scm_rights, stream_listener_disabled)
+{
+	.name = "UNIX-STREAM ",
+	.type = SOCK_STREAM,
+	.flags = 0,
+	.test_listener = true,
+	.disabled = true,
 };
 
 FIXTURE_VARIANT_ADD(scm_rights, stream_listener_oob)
@@ -63,6 +104,16 @@ FIXTURE_VARIANT_ADD(scm_rights, stream_listener_oob)
 	.type = SOCK_STREAM,
 	.flags = MSG_OOB,
 	.test_listener = true,
+	.disabled = false,
+};
+
+FIXTURE_VARIANT_ADD(scm_rights, stream_listener_oob_disabled)
+{
+	.name = "UNIX-STREAM ",
+	.type = SOCK_STREAM,
+	.flags = MSG_OOB,
+	.test_listener = true,
+	.disabled = true,
 };
 
 static int count_sockets(struct __test_metadata *_metadata,
@@ -105,6 +156,9 @@ FIXTURE_SETUP(scm_rights)
 	ret = unshare(CLONE_NEWNET);
 	ASSERT_EQ(0, ret);
 
+	if (variant->disabled)
+		return;
+
 	ret = count_sockets(_metadata, variant);
 	ASSERT_EQ(0, ret);
 }
@@ -113,6 +167,9 @@ FIXTURE_TEARDOWN(scm_rights)
 {
 	int ret;
 
+	if (variant->disabled)
+		return;
+
 	sleep(1);
 
 	ret = count_sockets(_metadata, variant);
@@ -121,6 +178,7 @@ FIXTURE_TEARDOWN(scm_rights)
 
 static void create_listeners(struct __test_metadata *_metadata,
 			     FIXTURE_DATA(scm_rights) *self,
+			     const FIXTURE_VARIANT(scm_rights) *variant,
 			     int n)
 {
 	struct sockaddr_un addr = {
@@ -140,6 +198,12 @@ static void create_listeners(struct __test_metadata *_metadata,
 		ret = listen(self->fd[i], -1);
 		ASSERT_EQ(0, ret);
 
+		if (variant->disabled) {
+			ret = setsockopt(self->fd[i], SOL_SOCKET, SO_PASSRIGHTS,
+					 &(int){0}, sizeof(int));
+			ASSERT_EQ(0, ret);
+		}
+
 		addrlen = sizeof(addr);
 		ret = getsockname(self->fd[i], (struct sockaddr *)&addr, &addrlen);
 		ASSERT_EQ(0, ret);
@@ -164,6 +228,12 @@ static void create_socketpairs(struct __test_metadata *_metadata,
 	for (i = 0; i < n * 2; i += 2) {
 		ret = socketpair(AF_UNIX, variant->type, 0, self->fd + i);
 		ASSERT_EQ(0, ret);
+
+		if (variant->disabled) {
+			ret = setsockopt(self->fd[i], SOL_SOCKET, SO_PASSRIGHTS,
+					 &(int){0}, sizeof(int));
+			ASSERT_EQ(0, ret);
+		}
 	}
 }
 
@@ -175,7 +245,7 @@ static void __create_sockets(struct __test_metadata *_metadata,
 	ASSERT_LE(n * 2, sizeof(self->fd) / sizeof(self->fd[0]));
 
 	if (variant->test_listener)
-		create_listeners(_metadata, self, n);
+		create_listeners(_metadata, self, variant, n);
 	else
 		create_socketpairs(_metadata, self, variant, n);
 }
@@ -230,7 +300,13 @@ void __send_fd(struct __test_metadata *_metadata,
 	int ret;
 
 	ret = sendmsg(self->fd[receiver * 2 + 1], &msg, variant->flags);
-	ASSERT_EQ(MSGLEN, ret);
+
+	if (variant->disabled) {
+		ASSERT_EQ(-1, ret);
+		ASSERT_EQ(-EPERM, -errno);
+	} else {
+		ASSERT_EQ(MSGLEN, ret);
+	}
 }
 
 #define create_sockets(n)					\
-- 
2.49.0


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

* Re: [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS.
  2025-05-19 20:57 [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
                   ` (8 preceding siblings ...)
  2025-05-19 20:58 ` [PATCH v5 net-next 9/9] selftest: af_unix: Test SO_PASSRIGHTS Kuniyuki Iwashima
@ 2025-05-28 11:40 ` Paolo Abeni
  2025-05-28 13:21   ` Paolo Abeni
  9 siblings, 1 reply; 15+ messages in thread
From: Paolo Abeni @ 2025-05-28 11:40 UTC (permalink / raw)
  To: Kuniyuki Iwashima, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima, netdev

On 5/19/25 10:57 PM, Kuniyuki Iwashima wrote:
> As long as recvmsg() or recvmmsg() is used with cmsg, it is not
> possible to avoid receiving file descriptors via SCM_RIGHTS.
> 
> This series introduces a new socket option, SO_PASSRIGHTS, to allow
> disabling SCM_RIGHTS.  The option is enabled by default.
> 
> See patch 8 for background/context.
> 
> This series is related to [0], but is split into a separate series,
> as most of the patches are specific to af_unix.
> 
> The v2 of the BPF LSM extension part will be posted later, once
> this series is merged into net-next and has landed in bpf-next.
> 
> [0]: https://lore.kernel.org/bpf/20250505215802.48449-1-kuniyu@amazon.com/

While booting a debug linus's tree with current net-next merged in, I
see a few splat at boot time:

[    4.556951] refcount_t: underflow; use-after-free.
[    4.557466] WARNING: CPU: 0 PID: 1 at lib/refcount.c:28
refcount_warn_saturate+0xae/0x150
[    4.558351] Modules linked in:
[    4.558692] CPU: 0 UID: 0 PID: 1 Comm: systemd Tainted: G    B
       6.15.0.net-next-6.16_0b31b995f034+ #3 PREEMPT(voluntary)
[    4.559887] Tainted: [B]=BAD_PAGE
[    4.560246] Hardware name: Red Hat KVM/RHEL, BIOS 1.16.3-2.el9 04/01/2014
[    4.560913] RIP: 0010:refcount_warn_saturate+0xae/0x150
[    4.561443] Code: c3 22 a3 03 01 e8 62 de df fe 0f 0b eb d1 80 3d b1
22 a3 03 00 75 c8 48 c7 c7 a0 77 73 b4 c6 05 a1 22 a3 03 01 e8 42 de df
fe <0f> 0b eb b1 80 3d 8f 22 a3 03 00 75 a8 48 c7 c7 60 78 73 b4 c6 05
[    4.563167] RSP: 0018:ffa000000001fac0 EFLAGS: 00010286
[    4.563708] RAX: 0000000000000000 RBX: ff11000129544680 RCX:
0000000000000000
[    4.564401] RDX: 0000000000000002 RSI: 0000000000000004 RDI:
0000000000000001
[    4.565110] RBP: 0000000000000003 R08: 0000000000000001 R09:
ffe21c002b27d8b1
[    4.565817] R10: ff110001593ec58b R11: 0000000000000000 R12:
ff11000129544600
[    4.566511] R13: ff11000129542bc0 R14: 0000000000000001 R15:
ff11000129542c40
[    4.567216] FS:  00007f2c798deb40(0000) GS:ff110001a1bb3000(0000)
knlGS:0000000000000000
[    4.568005] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    4.568579] CR2: 000055c3cefb01d8 CR3: 0000000120b4c003 CR4:
0000000000771ef0
[    4.569287] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[    4.569991] DR3: 0000000000000000 DR6: 00000000fffe07f0 DR7:
0000000000000400
[    4.570688] PKRU: 55555554
[    4.571005] Call Trace:
[    4.571285]  <TASK>
[    4.571538]  unix_release_sock+0x9ee/0x1040
[    4.571984]  ? rcu_is_watching+0x11/0xb0
[    4.572398]  ? __pfx_unix_release_sock+0x10/0x10
[    4.572881]  ? down_write+0xb4/0x220
[    4.573268]  ? __pfx_down_write+0x10/0x10
[    4.573687]  unix_release+0x88/0xe0
[    4.574074]  __sock_release+0xa3/0x260
[    4.574474]  sock_close+0x14/0x20
[    4.574842]  __fput+0x365/0xa80
[    4.575197]  fput_close_sync+0xd9/0x190
[    4.575599]  ? __pfx_fput_close_sync+0x10/0x10
[    4.576072]  __x64_sys_close+0x79/0xd0
[    4.576469]  do_syscall_64+0x8c/0x3d0
[    4.576873]  ? __pfx___handle_mm_fault+0x10/0x10
[    4.577354]  ? lock_release+0x121/0x190
[    4.577774]  ? rcu_is_watching+0x11/0xb0
[    4.578188]  ? __count_memcg_events+0x45c/0x5c0
[    4.578654]  ? count_memcg_events_mm.constprop.0+0xd4/0x200
[    4.579275]  ? rcu_is_watching+0x11/0xb0
[    4.579683]  ? lock_release+0x121/0x190
[    4.580100]  ? count_memcg_events_mm.constprop.0+0xd9/0x200
[    4.580658]  ? handle_mm_fault+0x3cf/0x670
[    4.581099]  ? exc_page_fault+0x58/0xc0
[    4.581505]  ? rcu_is_watching+0x11/0xb0
[    4.581925]  ? lock_release+0x121/0x190
[    4.582345]  ? do_user_addr_fault+0x489/0xb10
[    4.582806]  ? rcu_is_watching+0x11/0xb0
[    4.583221]  ? trace_irq_enable.constprop.0+0x14a/0x1b0
    4.583758]  ? clear_bhb_loop+0x60/0xb0
[    4.584165]  ? clear_bhb_loop+0x60/0xb0
[    4.584574]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[    4.585095] RIP: 0033:0x7f2c7a638417
[    4.585471] Code: ff e8 2d f6 01 00 66 2e 0f 1f 84 00 00 00 00 00 0f
1f 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 03 00 00 00 0f
05 <48> 3d 00 f0 ff ff 77 41 c3 48 83 ec 18 89 7c 24 0c e8 a3 7e f8 ff
[    4.587182] RSP: 002b:00007ffc7c624c58 EFLAGS: 00000246 ORIG_RAX:
0000000000000003
[    4.587921] RAX: ffffffffffffffda RBX: 00007f2c798de9d0 RCX:
00007f2c7a638417
[    4.588611] RDX: 000055c3cefcfeb0 RSI: 000055c3cef580c0 RDI:
0000000000000026
[    4.589318] RBP: 0000000000000026 R08: 00000000ffffffff R09:
0000000000000000
[    4.590019] R10: 0000000000000010 R11: 0000000000000246 R12:
000055c3cef54a10
[    4.590715] R13: 0000000000000000 R14: 00007ffc7c624db0 R15:
000055c3cef57cc0
[    4.591408]  </TASK>
[    4.591665] irq event stamp: 25199
[    4.592044] hardirqs last  enabled at (25199): [<ffffffffb1600e06>]
asm_sysvec_apic_timer_interrupt+0x16/0x20
[    4.592986] hardirqs last disabled at (25198): [<ffffffffb1a1df63>]
handle_softirqs+0x733/0x920
[    4.593824] softirqs last  enabled at (24848): [<ffffffffb1a1de28>]
handle_softirqs+0x5f8/0x920
[    4.594651] softirqs last disabled at (24843): [<ffffffffb1a1e2fb>]
__irq_exit_rcu+0x11b/0x270

I'm going to blindly test a local revert of this series and/or
a9194f88782afa1386641451a6c76beaa60485a0 and will report back.

/P


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

* Re: [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS.
  2025-05-28 11:40 ` [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Paolo Abeni
@ 2025-05-28 13:21   ` Paolo Abeni
  0 siblings, 0 replies; 15+ messages in thread
From: Paolo Abeni @ 2025-05-28 13:21 UTC (permalink / raw)
  To: Kuniyuki Iwashima, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima, netdev

On 5/28/25 1:40 PM, Paolo Abeni wrote:
> On 5/19/25 10:57 PM, Kuniyuki Iwashima wrote:
>> As long as recvmsg() or recvmmsg() is used with cmsg, it is not
>> possible to avoid receiving file descriptors via SCM_RIGHTS.
>>
>> This series introduces a new socket option, SO_PASSRIGHTS, to allow
>> disabling SCM_RIGHTS.  The option is enabled by default.
>>
>> See patch 8 for background/context.
>>
>> This series is related to [0], but is split into a separate series,
>> as most of the patches are specific to af_unix.
>>
>> The v2 of the BPF LSM extension part will be posted later, once
>> this series is merged into net-next and has landed in bpf-next.
>>
>> [0]: https://lore.kernel.org/bpf/20250505215802.48449-1-kuniyu@amazon.com/
> 
> While booting a debug linus's tree with current net-next merged in, I
> see a few splat at boot time:
> 
> [    4.556951] refcount_t: underflow; use-after-free.
> [    4.557466] WARNING: CPU: 0 PID: 1 at lib/refcount.c:28
> refcount_warn_saturate+0xae/0x150
> [    4.558351] Modules linked in:
> [    4.558692] CPU: 0 UID: 0 PID: 1 Comm: systemd Tainted: G    B
>        6.15.0.net-next-6.16_0b31b995f034+ #3 PREEMPT(voluntary)
> [    4.559887] Tainted: [B]=BAD_PAGE
> [    4.560246] Hardware name: Red Hat KVM/RHEL, BIOS 1.16.3-2.el9 04/01/2014
> [    4.560913] RIP: 0010:refcount_warn_saturate+0xae/0x150
> [    4.561443] Code: c3 22 a3 03 01 e8 62 de df fe 0f 0b eb d1 80 3d b1
> 22 a3 03 00 75 c8 48 c7 c7 a0 77 73 b4 c6 05 a1 22 a3 03 01 e8 42 de df
> fe <0f> 0b eb b1 80 3d 8f 22 a3 03 00 75 a8 48 c7 c7 60 78 73 b4 c6 05
> [    4.563167] RSP: 0018:ffa000000001fac0 EFLAGS: 00010286
> [    4.563708] RAX: 0000000000000000 RBX: ff11000129544680 RCX:
> 0000000000000000
> [    4.564401] RDX: 0000000000000002 RSI: 0000000000000004 RDI:
> 0000000000000001
> [    4.565110] RBP: 0000000000000003 R08: 0000000000000001 R09:
> ffe21c002b27d8b1
> [    4.565817] R10: ff110001593ec58b R11: 0000000000000000 R12:
> ff11000129544600
> [    4.566511] R13: ff11000129542bc0 R14: 0000000000000001 R15:
> ff11000129542c40
> [    4.567216] FS:  00007f2c798deb40(0000) GS:ff110001a1bb3000(0000)
> knlGS:0000000000000000
> [    4.568005] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [    4.568579] CR2: 000055c3cefb01d8 CR3: 0000000120b4c003 CR4:
> 0000000000771ef0
> [    4.569287] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> 0000000000000000
> [    4.569991] DR3: 0000000000000000 DR6: 00000000fffe07f0 DR7:
> 0000000000000400
> [    4.570688] PKRU: 55555554
> [    4.571005] Call Trace:
> [    4.571285]  <TASK>
> [    4.571538]  unix_release_sock+0x9ee/0x1040
> [    4.571984]  ? rcu_is_watching+0x11/0xb0
> [    4.572398]  ? __pfx_unix_release_sock+0x10/0x10
> [    4.572881]  ? down_write+0xb4/0x220
> [    4.573268]  ? __pfx_down_write+0x10/0x10
> [    4.573687]  unix_release+0x88/0xe0
> [    4.574074]  __sock_release+0xa3/0x260
> [    4.574474]  sock_close+0x14/0x20
> [    4.574842]  __fput+0x365/0xa80
> [    4.575197]  fput_close_sync+0xd9/0x190
> [    4.575599]  ? __pfx_fput_close_sync+0x10/0x10
> [    4.576072]  __x64_sys_close+0x79/0xd0
> [    4.576469]  do_syscall_64+0x8c/0x3d0
> [    4.576873]  ? __pfx___handle_mm_fault+0x10/0x10
> [    4.577354]  ? lock_release+0x121/0x190
> [    4.577774]  ? rcu_is_watching+0x11/0xb0
> [    4.578188]  ? __count_memcg_events+0x45c/0x5c0
> [    4.578654]  ? count_memcg_events_mm.constprop.0+0xd4/0x200
> [    4.579275]  ? rcu_is_watching+0x11/0xb0
> [    4.579683]  ? lock_release+0x121/0x190
> [    4.580100]  ? count_memcg_events_mm.constprop.0+0xd9/0x200
> [    4.580658]  ? handle_mm_fault+0x3cf/0x670
> [    4.581099]  ? exc_page_fault+0x58/0xc0
> [    4.581505]  ? rcu_is_watching+0x11/0xb0
> [    4.581925]  ? lock_release+0x121/0x190
> [    4.582345]  ? do_user_addr_fault+0x489/0xb10
> [    4.582806]  ? rcu_is_watching+0x11/0xb0
> [    4.583221]  ? trace_irq_enable.constprop.0+0x14a/0x1b0
>     4.583758]  ? clear_bhb_loop+0x60/0xb0
> [    4.584165]  ? clear_bhb_loop+0x60/0xb0
> [    4.584574]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
> [    4.585095] RIP: 0033:0x7f2c7a638417
> [    4.585471] Code: ff e8 2d f6 01 00 66 2e 0f 1f 84 00 00 00 00 00 0f
> 1f 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 03 00 00 00 0f
> 05 <48> 3d 00 f0 ff ff 77 41 c3 48 83 ec 18 89 7c 24 0c e8 a3 7e f8 ff
> [    4.587182] RSP: 002b:00007ffc7c624c58 EFLAGS: 00000246 ORIG_RAX:
> 0000000000000003
> [    4.587921] RAX: ffffffffffffffda RBX: 00007f2c798de9d0 RCX:
> 00007f2c7a638417
> [    4.588611] RDX: 000055c3cefcfeb0 RSI: 000055c3cef580c0 RDI:
> 0000000000000026
> [    4.589318] RBP: 0000000000000026 R08: 00000000ffffffff R09:
> 0000000000000000
> [    4.590019] R10: 0000000000000010 R11: 0000000000000246 R12:
> 000055c3cef54a10
> [    4.590715] R13: 0000000000000000 R14: 00007ffc7c624db0 R15:
> 000055c3cef57cc0
> [    4.591408]  </TASK>
> [    4.591665] irq event stamp: 25199
> [    4.592044] hardirqs last  enabled at (25199): [<ffffffffb1600e06>]
> asm_sysvec_apic_timer_interrupt+0x16/0x20
> [    4.592986] hardirqs last disabled at (25198): [<ffffffffb1a1df63>]
> handle_softirqs+0x733/0x920
> [    4.593824] softirqs last  enabled at (24848): [<ffffffffb1a1de28>]
> handle_softirqs+0x5f8/0x920
> [    4.594651] softirqs last disabled at (24843): [<ffffffffb1a1e2fb>]
> __irq_exit_rcu+0x11b/0x270
> 
> I'm going to blindly test a local revert of this series and/or
> a9194f88782afa1386641451a6c76beaa60485a0 and will report back.

The root cause was bad conflicts resolution on my side :/
Just ignore the above, I'm sorry for the noise.

Paolo


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

* Re: [PATCH v5 net-next 5/9] net: Restrict SO_PASS{CRED,PIDFD,SEC} to AF_{UNIX,NETLINK,BLUETOOTH}.
  2025-05-19 20:57 ` [PATCH v5 net-next 5/9] net: Restrict SO_PASS{CRED,PIDFD,SEC} to AF_{UNIX,NETLINK,BLUETOOTH} Kuniyuki Iwashima
@ 2025-06-09 11:14   ` Luca Boccassi
  2025-06-09 15:55     ` Kuniyuki Iwashima
  0 siblings, 1 reply; 15+ messages in thread
From: Luca Boccassi @ 2025-06-09 11:14 UTC (permalink / raw)
  To: Kuniyuki Iwashima, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Willem de Bruijn
  Cc: Simon Horman, Christian Brauner, Kuniyuki Iwashima, netdev

On Mon, 2025-05-19 at 13:57 -0700, Kuniyuki Iwashima wrote:
> SCM_CREDENTIALS and SCM_SECURITY can be recv()ed by calling
> scm_recv() or scm_recv_unix(), and SCM_PIDFD is only used by
> scm_recv_unix().
> 
> scm_recv() is called from AF_NETLINK and AF_BLUETOOTH.
> 
> scm_recv_unix() is literally called from AF_UNIX.
> 
> Let's restrict SO_PASSCRED and SO_PASSSEC to such sockets and
> SO_PASSPIDFD to AF_UNIX only.
> 
> Later, SOCK_PASS{CRED,PIDFD,SEC} will be moved to struct sock
> and united with another field.
> 
> Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
> Reviewed-by: Willem de Bruijn <willemb@google.com>
> ---
> v3:
>   * Return -EOPNOTSUPP in getsockopt() too
>   * Add CONFIG_SECURITY_NETWORK check for SO_PASSSEC
> 
> diff --git a/net/core/sock.c b/net/core/sock.c
> index d7d6d3a8efe5..fd5f9d3873c1 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c
> @@ -1221,12 +1221,21 @@ int sk_setsockopt(struct sock *sk, int level,
> int optname,
>  		}
>  		return -EPERM;
>  	case SO_PASSSEC:
> +		if (!IS_ENABLED(CONFIG_SECURITY_NETWORK) ||
> sk_may_scm_recv(sk))
> +			return -EOPNOTSUPP;

Hi,

Was this one meant to be !sk_may_scm_recv(sk) like in getsockopt below
by any chance?

We have a report that this is breaking AF_UNIX sockets with 6.16~rc1:

[    1.763019] systemd[1]: systemd-journald-dev-log.socket: SO_PASSSEC
failed: Operation not supported
[    1.763102] systemd[1]: systemd-journald.socket: SO_PASSSEC failed:
Operation not supported
[    1.763121] systemd[1]: systemd-journald.socket: SO_PASSSEC failed:
Operation not supported

https://github.com/systemd/systemd/issues/37783

> @@ -1956,6 +1971,9 @@ int sk_getsockopt(struct sock *sk, int level,
> int optname,
>  		break;
>  
>  	case SO_PASSSEC:
> +		if (!IS_ENABLED(CONFIG_SECURITY_NETWORK) ||
> !sk_may_scm_recv(sk))
> +			return -EOPNOTSUPP;
> +
>  		v.val = !!test_bit(SOCK_PASSSEC, &sock->flags);
>  		break;
>  

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

* Re: [PATCH v5 net-next 5/9] net: Restrict SO_PASS{CRED,PIDFD,SEC} to AF_{UNIX,NETLINK,BLUETOOTH}.
  2025-06-09 11:14   ` Luca Boccassi
@ 2025-06-09 15:55     ` Kuniyuki Iwashima
  2025-06-10 19:54       ` Kuniyuki Iwashima
  0 siblings, 1 reply; 15+ messages in thread
From: Kuniyuki Iwashima @ 2025-06-09 15:55 UTC (permalink / raw)
  To: bluca
  Cc: brauner, davem, edumazet, horms, kuba, kuni1840, kuniyu, netdev,
	pabeni, willemb

From: Luca Boccassi <bluca@debian.org>
Date: Mon, 09 Jun 2025 12:14:51 +0100
> On Mon, 2025-05-19 at 13:57 -0700, Kuniyuki Iwashima wrote:
> > SCM_CREDENTIALS and SCM_SECURITY can be recv()ed by calling
> > scm_recv() or scm_recv_unix(), and SCM_PIDFD is only used by
> > scm_recv_unix().
> > 
> > scm_recv() is called from AF_NETLINK and AF_BLUETOOTH.
> > 
> > scm_recv_unix() is literally called from AF_UNIX.
> > 
> > Let's restrict SO_PASSCRED and SO_PASSSEC to such sockets and
> > SO_PASSPIDFD to AF_UNIX only.
> > 
> > Later, SOCK_PASS{CRED,PIDFD,SEC} will be moved to struct sock
> > and united with another field.
> > 
> > Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
> > Reviewed-by: Willem de Bruijn <willemb@google.com>
> > ---
> > v3:
> >   * Return -EOPNOTSUPP in getsockopt() too
> >   * Add CONFIG_SECURITY_NETWORK check for SO_PASSSEC
> > 
> > diff --git a/net/core/sock.c b/net/core/sock.c
> > index d7d6d3a8efe5..fd5f9d3873c1 100644
> > --- a/net/core/sock.c
> > +++ b/net/core/sock.c
> > @@ -1221,12 +1221,21 @@ int sk_setsockopt(struct sock *sk, int level,
> > int optname,
> >  		}
> >  		return -EPERM;
> >  	case SO_PASSSEC:
> > +		if (!IS_ENABLED(CONFIG_SECURITY_NETWORK) ||
> > sk_may_scm_recv(sk))
> > +			return -EOPNOTSUPP;
> 
> Hi,
> 
> Was this one meant to be !sk_may_scm_recv(sk) like in getsockopt below
> by any chance?

Oops, but the next patch happened to fix it.

Will try to reproduce it.

> 
> We have a report that this is breaking AF_UNIX sockets with 6.16~rc1:
> 
> [    1.763019] systemd[1]: systemd-journald-dev-log.socket: SO_PASSSEC
> failed: Operation not supported
> [    1.763102] systemd[1]: systemd-journald.socket: SO_PASSSEC failed:
> Operation not supported
> [    1.763121] systemd[1]: systemd-journald.socket: SO_PASSSEC failed:
> Operation not supported
> 
> https://github.com/systemd/systemd/issues/37783

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

* Re: [PATCH v5 net-next 5/9] net: Restrict SO_PASS{CRED,PIDFD,SEC} to AF_{UNIX,NETLINK,BLUETOOTH}.
  2025-06-09 15:55     ` Kuniyuki Iwashima
@ 2025-06-10 19:54       ` Kuniyuki Iwashima
  0 siblings, 0 replies; 15+ messages in thread
From: Kuniyuki Iwashima @ 2025-06-10 19:54 UTC (permalink / raw)
  To: kuni1840
  Cc: bluca, brauner, davem, edumazet, horms, kuba, kuniyu, netdev,
	pabeni, willemb

From: Kuniyuki Iwashima <kuni1840@gmail.com>
Date: Mon,  9 Jun 2025 08:55:36 -0700
> From: Luca Boccassi <bluca@debian.org>
> Date: Mon, 09 Jun 2025 12:14:51 +0100
> > On Mon, 2025-05-19 at 13:57 -0700, Kuniyuki Iwashima wrote:
> > > SCM_CREDENTIALS and SCM_SECURITY can be recv()ed by calling
> > > scm_recv() or scm_recv_unix(), and SCM_PIDFD is only used by
> > > scm_recv_unix().
> > > 
> > > scm_recv() is called from AF_NETLINK and AF_BLUETOOTH.
> > > 
> > > scm_recv_unix() is literally called from AF_UNIX.
> > > 
> > > Let's restrict SO_PASSCRED and SO_PASSSEC to such sockets and
> > > SO_PASSPIDFD to AF_UNIX only.
> > > 
> > > Later, SOCK_PASS{CRED,PIDFD,SEC} will be moved to struct sock
> > > and united with another field.
> > > 
> > > Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
> > > Reviewed-by: Willem de Bruijn <willemb@google.com>
> > > ---
> > > v3:
> > >   * Return -EOPNOTSUPP in getsockopt() too
> > >   * Add CONFIG_SECURITY_NETWORK check for SO_PASSSEC
> > > 
> > > diff --git a/net/core/sock.c b/net/core/sock.c
> > > index d7d6d3a8efe5..fd5f9d3873c1 100644
> > > --- a/net/core/sock.c
> > > +++ b/net/core/sock.c
> > > @@ -1221,12 +1221,21 @@ int sk_setsockopt(struct sock *sk, int level,
> > > int optname,
> > >  		}
> > >  		return -EPERM;
> > >  	case SO_PASSSEC:
> > > +		if (!IS_ENABLED(CONFIG_SECURITY_NETWORK) ||
> > > sk_may_scm_recv(sk))
> > > +			return -EOPNOTSUPP;
> > 
> > Hi,
> > 
> > Was this one meant to be !sk_may_scm_recv(sk) like in getsockopt below
> > by any chance?
> 
> Oops, but the next patch happened to fix it.
> 
> Will try to reproduce it.
> 
> > 
> > We have a report that this is breaking AF_UNIX sockets with 6.16~rc1:
> > 
> > [    1.763019] systemd[1]: systemd-journald-dev-log.socket: SO_PASSSEC
> > failed: Operation not supported
> > [    1.763102] systemd[1]: systemd-journald.socket: SO_PASSSEC failed:
> > Operation not supported
> > [    1.763121] systemd[1]: systemd-journald.socket: SO_PASSSEC failed:
> > Operation not supported

This was just a warning and nothing broken as mentioned in the
thread below.

> > 
> > https://github.com/systemd/systemd/issues/37783

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

end of thread, other threads:[~2025-06-10 19:55 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-19 20:57 [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
2025-05-19 20:57 ` [PATCH v5 net-next 1/9] af_unix: Factorise test_bit() for SOCK_PASSCRED and SOCK_PASSPIDFD Kuniyuki Iwashima
2025-05-19 20:57 ` [PATCH v5 net-next 2/9] af_unix: Don't pass struct socket to maybe_add_creds() Kuniyuki Iwashima
2025-05-19 20:57 ` [PATCH v5 net-next 3/9] scm: Move scm_recv() from scm.h to scm.c Kuniyuki Iwashima
2025-05-19 20:57 ` [PATCH v5 net-next 4/9] tcp: Restrict SO_TXREHASH to TCP socket Kuniyuki Iwashima
2025-05-19 20:57 ` [PATCH v5 net-next 5/9] net: Restrict SO_PASS{CRED,PIDFD,SEC} to AF_{UNIX,NETLINK,BLUETOOTH} Kuniyuki Iwashima
2025-06-09 11:14   ` Luca Boccassi
2025-06-09 15:55     ` Kuniyuki Iwashima
2025-06-10 19:54       ` Kuniyuki Iwashima
2025-05-19 20:57 ` [PATCH v5 net-next 6/9] af_unix: Move SOCK_PASS{CRED,PIDFD,SEC} to struct sock Kuniyuki Iwashima
2025-05-19 20:57 ` [PATCH v5 net-next 7/9] af_unix: Inherit sk_flags at connect() Kuniyuki Iwashima
2025-05-19 20:57 ` [PATCH v5 net-next 8/9] af_unix: Introduce SO_PASSRIGHTS Kuniyuki Iwashima
2025-05-19 20:58 ` [PATCH v5 net-next 9/9] selftest: af_unix: Test SO_PASSRIGHTS Kuniyuki Iwashima
2025-05-28 11:40 ` [PATCH v5 net-next 0/9] af_unix: Introduce SO_PASSRIGHTS Paolo Abeni
2025-05-28 13:21   ` Paolo Abeni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).