[PATCH v2 bpf-next 2/4] af_unix: Call security_unix_may_send() in sendmsg() for all socket types

Kuniyuki Iwashima kuni1840 at gmail.com
Fri Jun 13 22:22:14 UTC 2025


From: Kuniyuki Iwashima <kuniyu at google.com>

Currently, security_unix_may_send() is invoked only for SOCK_DGRAM
sockets during connect() and sendmsg().

For SOCK_STREAM and SOCK_SEQPACKET sockets, an equivalent check
already occurs during connect(), making an additional hook in
sendmsg() unnecessary.

However, we want to leverage BPF LSM to inspect UNIXCB(skb) during
sendmsg().

As a preparation, let's call security_unix_may_send() for SOCK_STREAM
and SOCK_SEQPACKET in sendmsg().

Note that SELinux, SMACK, and Landlock use security_unix_may_send().
To avoid unintentionally triggering the hook for SOCK_STREAM and
SOCK_SEQPACKET, the socket type check is added in each LSM hooks.

Signed-off-by: Kuniyuki Iwashima <kuniyu at google.com>
---
 net/unix/af_unix.c         | 30 +++++++++++++++++++++---------
 security/landlock/task.c   |  3 +++
 security/selinux/hooks.c   |  3 +++
 security/smack/smack_lsm.c |  3 +++
 4 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 6865da79ad1c..bcbe0c86e001 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2170,11 +2170,9 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 		goto out_unlock;
 	}
 
-	if (sk->sk_type != SOCK_SEQPACKET) {
-		err = security_unix_may_send(sk, other);
-		if (err)
-			goto out_unlock;
-	}
+	err = security_unix_may_send(sk, other);
+	if (err)
+		goto out_unlock;
 
 	/* other == sk && unix_peer(other) != sk if
 	 * - unix_peer(sk) == NULL, destination address bound to sk
@@ -2280,6 +2278,12 @@ static int queue_oob(struct sock *sk, struct msghdr *msg, struct sock *other,
 		goto out_unlock;
 	}
 
+	if (!fds_sent) {
+		err = security_unix_may_send(sk, other);
+		if (err)
+			goto out_unlock;
+	}
+
 	unix_maybe_add_creds(skb, sk, other);
 	scm_stat_add(other, skb);
 
@@ -2372,8 +2376,6 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
 		if (err < 0)
 			goto out_free;
 
-		fds_sent = true;
-
 		if (unlikely(msg->msg_flags & MSG_SPLICE_PAGES)) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			err = skb_splice_from_iter(skb, &msg->msg_iter, size,
@@ -2399,9 +2401,16 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
 			goto out_pipe_unlock;
 
 		if (UNIXCB(skb).fp && !other->sk_scm_rights) {
-			unix_state_unlock(other);
 			err = -EPERM;
-			goto out_free;
+			goto out_unlock;
+		}
+
+		if (!fds_sent) {
+			err = security_unix_may_send(sk, other);
+			if (err)
+				goto out_unlock;
+
+			fds_sent = true;
 		}
 
 		unix_maybe_add_creds(skb, sk, other);
@@ -2425,6 +2434,9 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
 
 	return sent;
 
+out_unlock:
+	unix_state_unlock(other);
+	goto out_free;
 out_pipe_unlock:
 	unix_state_unlock(other);
 out_pipe:
diff --git a/security/landlock/task.c b/security/landlock/task.c
index d7db70790a33..6bc6f3027790 100644
--- a/security/landlock/task.c
+++ b/security/landlock/task.c
@@ -305,6 +305,9 @@ static int hook_unix_may_send(struct sock *const sk,
 	if (!subject)
 		return 0;
 
+	if (sk->sk_type != SOCK_DGRAM)
+		return 0;
+
 	/*
 	 * Checks if this datagram socket was already allowed to be connected
 	 * to other.
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 07101a2bf942..904926ef9ee8 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5184,6 +5184,9 @@ static int selinux_socket_unix_may_send(struct sock *sk,
 	struct common_audit_data ad;
 	struct lsm_network_audit net;
 
+	if (sk->sk_type != SOCK_DGRAM)
+		return 0;
+
 	ad_net_init_from_sk(&ad, &net, other);
 
 	return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 9bb00c0df373..20fe1d22210e 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3903,6 +3903,9 @@ static int smack_unix_may_send(struct sock *sk, struct sock *other)
 	smk_ad_setfield_u_net_sk(&ad, other);
 #endif
 
+	if (sk->sk_type != SOCK_DGRAM)
+		return 0;
+
 	if (smack_privileged(CAP_MAC_OVERRIDE))
 		return 0;
 
-- 
2.49.0




More information about the Linux-security-module-archive mailing list