From: Kuniyuki Iwashima <kuniyu@xxxxxxxxxx> SO_PASSRIGHTS is not flexible as it cannot control what types of file descriptors are allowed to be passed. Let's pass skb to security_unix_may_send() so that we can implement more fine-grained filtering logic with BPF LSM. Note that only the LSM_HOOK() macro uses the __nullable suffix for skb to inform the verifier that the skb could be NULL at connect(). Without it, I was able to load a bpf prog without NULL check against skb. Signed-off-by: Kuniyuki Iwashima <kuniyu@xxxxxxxxxx> --- include/linux/lsm_hook_defs.h | 3 ++- include/linux/security.h | 5 +++-- net/unix/af_unix.c | 8 ++++---- security/landlock/task.c | 3 ++- security/security.c | 5 +++-- security/selinux/hooks.c | 3 ++- security/smack/smack_lsm.c | 3 ++- 7 files changed, 18 insertions(+), 12 deletions(-) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 9be001922e0b..80edfe85214e 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -318,7 +318,8 @@ LSM_HOOK(int, 0, watch_key, struct key *key) #ifdef CONFIG_SECURITY_NETWORK LSM_HOOK(int, 0, unix_stream_connect, struct sock *sock, struct sock *other, struct sock *newsk) -LSM_HOOK(int, 0, unix_may_send, struct sock *sock, struct sock *other) +LSM_HOOK(int, 0, unix_may_send, struct sock *sock, struct sock *other, + struct sk_buff *skb__nullable) LSM_HOOK(int, 0, socket_create, int family, int type, int protocol, int kern) LSM_HOOK(int, 0, socket_post_create, struct socket *sock, int family, int type, int protocol, int kern) diff --git a/include/linux/security.h b/include/linux/security.h index 36aa7030e16d..922618a98f15 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1625,7 +1625,7 @@ static inline int security_watch_key(struct key *key) int security_netlink_send(struct sock *sk, struct sk_buff *skb); int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk); -int security_unix_may_send(struct sock *sk, struct sock *other); +int security_unix_may_send(struct sock *sk, struct sock *other, struct sk_buff *skb); int security_socket_create(int family, int type, int protocol, int kern); int security_socket_post_create(struct socket *sock, int family, int type, int protocol, int kern); @@ -1692,7 +1692,8 @@ static inline int security_unix_stream_connect(struct sock *sock, } static inline int security_unix_may_send(struct sock *sk, - struct sock *other) + struct sock *other, + struct sk_buff *skb) { return 0; } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index bcbe0c86e001..fd6b5e17f6c4 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1516,7 +1516,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, if (!unix_may_send(sk, other)) goto out_unlock; - err = security_unix_may_send(sk, other); + err = security_unix_may_send(sk, other, NULL); if (err) goto out_unlock; @@ -2170,7 +2170,7 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, goto out_unlock; } - err = security_unix_may_send(sk, other); + err = security_unix_may_send(sk, other, skb); if (err) goto out_unlock; @@ -2279,7 +2279,7 @@ static int queue_oob(struct sock *sk, struct msghdr *msg, struct sock *other, } if (!fds_sent) { - err = security_unix_may_send(sk, other); + err = security_unix_may_send(sk, other, skb); if (err) goto out_unlock; } @@ -2406,7 +2406,7 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, } if (!fds_sent) { - err = security_unix_may_send(sk, other); + err = security_unix_may_send(sk, other, skb); if (err) goto out_unlock; diff --git a/security/landlock/task.c b/security/landlock/task.c index 6bc6f3027790..f243edb036a7 100644 --- a/security/landlock/task.c +++ b/security/landlock/task.c @@ -295,7 +295,8 @@ static int hook_unix_stream_connect(struct sock *const sock, } static int hook_unix_may_send(struct sock *const sk, - struct sock *const other) + struct sock *const other, + struct sk_buff *skb) { size_t handle_layer; const struct landlock_cred_security *const subject = diff --git a/security/security.c b/security/security.c index 3bd8eec01d05..3362e5b6764f 100644 --- a/security/security.c +++ b/security/security.c @@ -4531,9 +4531,10 @@ EXPORT_SYMBOL(security_unix_stream_connect); * * Return: Returns 0 if permission is granted. */ -int security_unix_may_send(struct sock *sk, struct sock *other) +int security_unix_may_send(struct sock *sk, struct sock *other, + struct sk_buff *skb) { - return call_int_hook(unix_may_send, sk, other); + return call_int_hook(unix_may_send, sk, other, skb); } EXPORT_SYMBOL(security_unix_may_send); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 904926ef9ee8..dec0abbc60d5 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5177,7 +5177,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock, } static int selinux_socket_unix_may_send(struct sock *sk, - struct sock *other) + struct sock *other, + struct sk_buff *skb) { struct sk_security_struct *ssec = selinux_sock(sk); struct sk_security_struct *osec = selinux_sock(other); diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 20fe1d22210e..2fd2c1be5bbb 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3889,7 +3889,8 @@ static int smack_unix_stream_connect(struct sock *sock, * Return 0 if a subject with the smack of sock could access * an object with the smack of other, otherwise an error code */ -static int smack_unix_may_send(struct sock *sk, struct sock *other) +static int smack_unix_may_send(struct sock *sk, struct sock *other, + struct sk_buff *skb) { struct socket_smack *ssp = smack_sock(sk); struct socket_smack *osp = smack_sock(other); -- 2.49.0