Skip to content

Commit e7db1e4

Browse files
q2venintel-lab-lkp
authored andcommitted
bpf: Add kfunc to scrub SCM_RIGHTS at security_unix_may_send().
As Christian Brauner said [0], 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 that close() for unwanted file descriptors could block longer because the last fput() could occur on the receiver 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 filter SCM_RIGHTS on the sender side. Let's add a new kfunc to scrub all file descriptors from skb in sendmsg(). This allows the receiver to keep recv()ing the bare data and disallows the sender to impose the potential slowness of the last fput(). If necessary, we can add more granular filtering per file descriptor after refactoring GC code and adding some fd-to-file helpers for BPF. Sample: SEC("lsm/unix_may_send") int BPF_PROG(unix_scrub_scm_rights, struct socket *sock, struct socket *other, struct sk_buff *skb) { struct unix_skb_parms *cb; if (skb && bpf_unix_scrub_fds(skb)) return -EPERM; return 0; } Link: https://lore.kernel.org/netdev/20250502-fanden-unbeschadet-89973225255f@brauner/ #[0] Link: https://github.com/systemd/systemd/blob/v257.5/src/basic/fd-util.c#L612-L628 #[1] Signed-off-by: Kuniyuki Iwashima <[email protected]>
1 parent d01e56a commit e7db1e4

File tree

3 files changed

+33
-2
lines changed

3 files changed

+33
-2
lines changed

include/net/af_unix.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,5 @@ struct unix_sock {
5858
#define unix_state_lock(s) spin_lock(&unix_sk(s)->lock)
5959
#define unix_state_unlock(s) spin_unlock(&unix_sk(s)->lock)
6060

61+
int unix_scrub_fds(struct sk_buff *skb);
6162
#endif

net/core/filter.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
#include <net/mptcp.h>
8383
#include <net/netfilter/nf_conntrack_bpf.h>
8484
#include <net/netkit.h>
85-
#include <linux/un.h>
85+
#include <net/af_unix.h>
8686
#include <net/xdp_sock_drv.h>
8787
#include <net/inet_dscp.h>
8888

@@ -12153,6 +12153,11 @@ __bpf_kfunc int bpf_sock_ops_enable_tx_tstamp(struct bpf_sock_ops_kern *skops,
1215312153
return 0;
1215412154
}
1215512155

12156+
__bpf_kfunc int bpf_unix_scrub_fds(struct sk_buff *skb)
12157+
{
12158+
return unix_scrub_fds(skb);
12159+
}
12160+
1215612161
__bpf_kfunc_end_defs();
1215712162

1215812163
int bpf_dynptr_from_skb_rdonly(struct __sk_buff *skb, u64 flags,
@@ -12190,6 +12195,10 @@ BTF_KFUNCS_START(bpf_kfunc_check_set_sock_ops)
1219012195
BTF_ID_FLAGS(func, bpf_sock_ops_enable_tx_tstamp, KF_TRUSTED_ARGS)
1219112196
BTF_KFUNCS_END(bpf_kfunc_check_set_sock_ops)
1219212197

12198+
BTF_KFUNCS_START(bpf_kfunc_check_set_scm_rights)
12199+
BTF_ID_FLAGS(func, bpf_unix_scrub_fds, KF_TRUSTED_ARGS)
12200+
BTF_KFUNCS_END(bpf_kfunc_check_set_scm_rights)
12201+
1219312202
static const struct btf_kfunc_id_set bpf_kfunc_set_skb = {
1219412203
.owner = THIS_MODULE,
1219512204
.set = &bpf_kfunc_check_set_skb,
@@ -12215,6 +12224,11 @@ static const struct btf_kfunc_id_set bpf_kfunc_set_sock_ops = {
1221512224
.set = &bpf_kfunc_check_set_sock_ops,
1221612225
};
1221712226

12227+
static const struct btf_kfunc_id_set bpf_kfunc_set_scm_rights = {
12228+
.owner = THIS_MODULE,
12229+
.set = &bpf_kfunc_check_set_scm_rights,
12230+
};
12231+
1221812232
static int __init bpf_kfunc_init(void)
1221912233
{
1222012234
int ret;
@@ -12234,7 +12248,8 @@ static int __init bpf_kfunc_init(void)
1223412248
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
1223512249
&bpf_kfunc_set_sock_addr);
1223612250
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &bpf_kfunc_set_tcp_reqsk);
12237-
return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SOCK_OPS, &bpf_kfunc_set_sock_ops);
12251+
ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SOCK_OPS, &bpf_kfunc_set_sock_ops);
12252+
return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &bpf_kfunc_set_scm_rights);
1223812253
}
1223912254
late_initcall(bpf_kfunc_init);
1224012255

net/unix/af_unix.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,6 +1885,21 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
18851885
return err;
18861886
}
18871887

1888+
int unix_scrub_fds(struct sk_buff *skb)
1889+
{
1890+
struct scm_cookie scm = {};
1891+
1892+
if (skb->destructor != unix_destruct_scm)
1893+
return -EINVAL;
1894+
1895+
if (UNIXCB(skb).fp) {
1896+
unix_detach_fds(&scm, skb);
1897+
scm_fp_destroy(&scm);
1898+
}
1899+
1900+
return 0;
1901+
}
1902+
18881903
static bool unix_passcred_enabled(const struct socket *sock,
18891904
const struct sock *other)
18901905
{

0 commit comments

Comments
 (0)