Skip to content

Commit 85a9003

Browse files
q2venintel-lab-lkp
authored andcommitted
selftest: bpf: Add test for bpf_unix_scrub_fds().
This test performs the following for all AF_UNIX socket types 1. Create a socket pair (sender and receiver) 2. Send the receiver's fd from the sender to the receiver 3. Receive the fd 4. Attach a BPF LSM prog that scrubs SCM_RIGHTS fds 5. Send the receiver's fd from the sender to the receiver 6. Check if the fd was scrubbed 7. Detach the LSM prog How to run: # make -C tools/testing/selftests/bpf/ # ./tools/testing/selftests/bpf/test_progs -t lsm_unix_may_send ... torvalds#175/1 lsm_unix_may_send/SOCK_STREAM:OK torvalds#175/2 lsm_unix_may_send/SOCK_DGRAM:OK torvalds#175/3 lsm_unix_may_send/SOCK_SEQPACKET:OK torvalds#175 lsm_unix_may_send:OK Summary: 1/3 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Kuniyuki Iwashima <[email protected]>
1 parent e7db1e4 commit 85a9003

File tree

2 files changed

+190
-0
lines changed

2 files changed

+190
-0
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright Amazon.com Inc. or its affiliates. */
3+
4+
#include "test_progs.h"
5+
#include "lsm_unix_may_send.skel.h"
6+
7+
#define MSG_HELLO "Hello"
8+
#define MSG_WORLD "World"
9+
#define MSG_LEN 5
10+
11+
struct scm_rights {
12+
struct cmsghdr cmsghdr;
13+
int fd;
14+
};
15+
16+
static int send_fd(int sender_fd, int receiver_fd)
17+
{
18+
struct scm_rights cmsg = {};
19+
struct msghdr msg = {};
20+
struct iovec iov = {};
21+
int ret;
22+
23+
msg.msg_iov = &iov;
24+
msg.msg_iovlen = 1;
25+
msg.msg_control = &cmsg;
26+
msg.msg_controllen = CMSG_SPACE(sizeof(cmsg.fd));
27+
28+
iov.iov_base = MSG_HELLO;
29+
iov.iov_len = MSG_LEN;
30+
31+
cmsg.cmsghdr.cmsg_len = CMSG_LEN(sizeof(cmsg.fd));
32+
cmsg.cmsghdr.cmsg_level = SOL_SOCKET;
33+
cmsg.cmsghdr.cmsg_type = SCM_RIGHTS;
34+
cmsg.fd = receiver_fd;
35+
36+
ret = sendmsg(sender_fd, &msg, 0);
37+
if (!ASSERT_EQ(ret, MSG_LEN, "sendmsg(Hello)"))
38+
return -EINVAL;
39+
40+
ret = send(sender_fd, MSG_WORLD, MSG_LEN, 0);
41+
if (!ASSERT_EQ(ret, MSG_LEN, "sendmsg(World)"))
42+
return -EINVAL;
43+
44+
return 0;
45+
}
46+
47+
static int recv_fd(int receiver_fd, bool lsm_attached)
48+
{
49+
struct scm_rights cmsg = {};
50+
struct msghdr msg = {};
51+
char buf[MSG_LEN] = {};
52+
struct iovec iov = {};
53+
int ret;
54+
55+
msg.msg_iov = &iov;
56+
msg.msg_iovlen = 1;
57+
msg.msg_control = &cmsg;
58+
msg.msg_controllen = CMSG_SPACE(sizeof(cmsg.fd));
59+
60+
iov.iov_base = buf;
61+
iov.iov_len = sizeof(buf);
62+
63+
ret = recvmsg(receiver_fd, &msg, 0);
64+
if (!ASSERT_EQ(ret, MSG_LEN, "recvmsg(Hello) length") ||
65+
!ASSERT_STRNEQ(buf, MSG_HELLO, MSG_LEN, "recvmsg(Hello) data"))
66+
return -EINVAL;
67+
68+
if (lsm_attached) {
69+
if (!ASSERT_ERR_PTR(CMSG_FIRSTHDR(&msg), "cmsg filtered"))
70+
return -EINVAL;
71+
} else {
72+
if (!ASSERT_OK_PTR(CMSG_FIRSTHDR(&msg), "cmsg sent") ||
73+
!ASSERT_EQ(cmsg.cmsghdr.cmsg_len, CMSG_LEN(sizeof(cmsg.fd)), "cmsg_len") ||
74+
!ASSERT_EQ(cmsg.cmsghdr.cmsg_level, SOL_SOCKET, "cmsg_level") ||
75+
!ASSERT_EQ(cmsg.cmsghdr.cmsg_type, SCM_RIGHTS, "cmsg_type"))
76+
return -EINVAL;
77+
78+
receiver_fd = cmsg.fd;
79+
}
80+
81+
memset(buf, 0, sizeof(buf));
82+
83+
ret = recv(receiver_fd, buf, sizeof(buf), 0);
84+
if (!ASSERT_EQ(ret, MSG_LEN, "recvmsg(World) length") ||
85+
!ASSERT_STRNEQ(buf, MSG_WORLD, MSG_LEN, "recvmsg(World) data"))
86+
return -EINVAL;
87+
88+
return 0;
89+
}
90+
91+
static void test_scm_rights(struct lsm_unix_may_send *skel, int type)
92+
{
93+
struct bpf_link *link;
94+
int socket_fds[2];
95+
int err;
96+
97+
err = socketpair(AF_UNIX, type, 0, socket_fds);
98+
if (!ASSERT_EQ(err, 0, "socketpair"))
99+
return;
100+
101+
err = send_fd(socket_fds[0], socket_fds[1]);
102+
if (err)
103+
goto close;
104+
105+
err = recv_fd(socket_fds[1], false);
106+
if (err)
107+
goto close;
108+
109+
link = bpf_program__attach_lsm(skel->progs.unix_scrub_scm_rights);
110+
if (!ASSERT_OK_PTR(link, "attach lsm"))
111+
goto close;
112+
113+
err = send_fd(socket_fds[0], socket_fds[1]);
114+
if (err)
115+
goto close;
116+
117+
err = recv_fd(socket_fds[1], true);
118+
if (err)
119+
goto close;
120+
121+
err = bpf_link__destroy(link);
122+
ASSERT_EQ(err, 0, "destroy lsm");
123+
close:
124+
close(socket_fds[0]);
125+
close(socket_fds[1]);
126+
}
127+
128+
struct sk_type {
129+
char name[16];
130+
int type;
131+
} sk_types[] = {
132+
{
133+
.name = "SOCK_STREAM",
134+
.type = SOCK_STREAM,
135+
},
136+
{
137+
.name = "SOCK_DGRAM",
138+
.type = SOCK_DGRAM,
139+
},
140+
{
141+
.name = "SOCK_SEQPACKET",
142+
.type = SOCK_SEQPACKET,
143+
},
144+
};
145+
146+
void test_lsm_unix_may_send(void)
147+
{
148+
struct lsm_unix_may_send *skel;
149+
int i;
150+
151+
skel = lsm_unix_may_send__open_and_load();
152+
if (!ASSERT_OK_PTR(skel, "load skel"))
153+
return;
154+
155+
for (i = 0; i < ARRAY_SIZE(sk_types); i++)
156+
if (test__start_subtest(sk_types[i].name))
157+
test_scm_rights(skel, sk_types[i].type);
158+
159+
lsm_unix_may_send__destroy(skel);
160+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright Amazon.com Inc. or its affiliates. */
3+
4+
#include "vmlinux.h"
5+
#include <bpf/bpf_tracing.h>
6+
7+
#ifndef EPERM
8+
#define EPERM 1
9+
#endif
10+
11+
SEC("lsm/unix_may_send")
12+
int BPF_PROG(unix_scrub_scm_rights,
13+
struct socket *sock, struct socket *other, struct sk_buff *skb)
14+
{
15+
struct unix_skb_parms *cb;
16+
17+
if (!skb)
18+
return 0;
19+
20+
cb = (struct unix_skb_parms *)skb->cb;
21+
if (!cb->fp)
22+
return 0;
23+
24+
if (bpf_unix_scrub_fds(skb))
25+
return -EPERM;
26+
27+
return 0;
28+
}
29+
30+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)