]> Git Repo - J-linux.git/blob - tools/testing/selftests/bpf/prog_tests/sock_create.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / bpf / prog_tests / sock_create.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/bpf.h>
3 #include <test_progs.h>
4 #include "cgroup_helpers.h"
5
6 static char bpf_log_buf[4096];
7 static bool verbose;
8
9 enum sock_create_test_error {
10         OK = 0,
11         DENY_CREATE,
12 };
13
14 static struct sock_create_test {
15         const char                      *descr;
16         const struct bpf_insn           insns[64];
17         enum bpf_attach_type            attach_type;
18         enum bpf_attach_type            expected_attach_type;
19
20         int                             domain;
21         int                             type;
22         int                             protocol;
23
24         int                             optname;
25         int                             optval;
26         enum sock_create_test_error     error;
27 } tests[] = {
28         {
29                 .descr = "AF_INET set priority",
30                 .insns = {
31                         /* r3 = 123 (priority) */
32                         BPF_MOV64_IMM(BPF_REG_3, 123),
33                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
34                                     offsetof(struct bpf_sock, priority)),
35
36                         /* return 1 */
37                         BPF_MOV64_IMM(BPF_REG_0, 1),
38                         BPF_EXIT_INSN(),
39                 },
40                 .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
41                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
42
43                 .domain = AF_INET,
44                 .type = SOCK_DGRAM,
45
46                 .optname = SO_PRIORITY,
47                 .optval = 123,
48         },
49         {
50                 .descr = "AF_INET6 set priority",
51                 .insns = {
52                         /* r3 = 123 (priority) */
53                         BPF_MOV64_IMM(BPF_REG_3, 123),
54                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
55                                     offsetof(struct bpf_sock, priority)),
56
57                         /* return 1 */
58                         BPF_MOV64_IMM(BPF_REG_0, 1),
59                         BPF_EXIT_INSN(),
60                 },
61                 .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
62                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
63
64                 .domain = AF_INET6,
65                 .type = SOCK_DGRAM,
66
67                 .optname = SO_PRIORITY,
68                 .optval = 123,
69         },
70         {
71                 .descr = "AF_INET set mark",
72                 .insns = {
73                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
74
75                         /* get uid of process */
76                         BPF_EMIT_CALL(BPF_FUNC_get_current_uid_gid),
77                         BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffffffff),
78
79                         /* if uid is 0, use given mark(666), else use uid as the mark */
80                         BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
81                         BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
82                         BPF_MOV64_IMM(BPF_REG_3, 666),
83
84                         BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
85                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
86                                     offsetof(struct bpf_sock, mark)),
87
88                         /* return 1 */
89                         BPF_MOV64_IMM(BPF_REG_0, 1),
90                         BPF_EXIT_INSN(),
91                 },
92                 .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
93                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
94
95                 .domain = AF_INET,
96                 .type = SOCK_DGRAM,
97
98                 .optname = SO_MARK,
99                 .optval = 666,
100         },
101         {
102                 .descr = "AF_INET6 set mark",
103                 .insns = {
104                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
105
106                         /* get uid of process */
107                         BPF_EMIT_CALL(BPF_FUNC_get_current_uid_gid),
108                         BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffffffff),
109
110                         /* if uid is 0, use given mark(666), else use uid as the mark */
111                         BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
112                         BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
113                         BPF_MOV64_IMM(BPF_REG_3, 666),
114
115                         BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
116                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
117                                     offsetof(struct bpf_sock, mark)),
118
119                         /* return 1 */
120                         BPF_MOV64_IMM(BPF_REG_0, 1),
121                         BPF_EXIT_INSN(),
122                 },
123                 .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
124                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
125
126                 .domain = AF_INET6,
127                 .type = SOCK_DGRAM,
128
129                 .optname = SO_MARK,
130                 .optval = 666,
131         },
132         {
133                 .descr = "AF_INET bound to iface",
134                 .insns = {
135                         /* r3 = 1 (lo interface) */
136                         BPF_MOV64_IMM(BPF_REG_3, 1),
137                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
138                                     offsetof(struct bpf_sock, bound_dev_if)),
139
140                         /* return 1 */
141                         BPF_MOV64_IMM(BPF_REG_0, 1),
142                         BPF_EXIT_INSN(),
143                 },
144                 .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
145                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
146
147                 .domain = AF_INET,
148                 .type = SOCK_DGRAM,
149
150                 .optname = SO_BINDTOIFINDEX,
151                 .optval = 1,
152         },
153         {
154                 .descr = "AF_INET6 bound to iface",
155                 .insns = {
156                         /* r3 = 1 (lo interface) */
157                         BPF_MOV64_IMM(BPF_REG_3, 1),
158                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
159                                     offsetof(struct bpf_sock, bound_dev_if)),
160
161                         /* return 1 */
162                         BPF_MOV64_IMM(BPF_REG_0, 1),
163                         BPF_EXIT_INSN(),
164                 },
165                 .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
166                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
167
168                 .domain = AF_INET6,
169                 .type = SOCK_DGRAM,
170
171                 .optname = SO_BINDTOIFINDEX,
172                 .optval = 1,
173         },
174         {
175                 .descr = "block AF_INET, SOCK_DGRAM, IPPROTO_ICMP socket",
176                 .insns = {
177                         BPF_MOV64_IMM(BPF_REG_0, 1),    /* r0 = verdict */
178
179                         /* sock->family == AF_INET */
180                         BPF_LDX_MEM(BPF_H, BPF_REG_2, BPF_REG_1,
181                                     offsetof(struct bpf_sock, family)),
182                         BPF_JMP_IMM(BPF_JNE, BPF_REG_2, AF_INET, 5),
183
184                         /* sock->type == SOCK_DGRAM */
185                         BPF_LDX_MEM(BPF_H, BPF_REG_2, BPF_REG_1,
186                                     offsetof(struct bpf_sock, type)),
187                         BPF_JMP_IMM(BPF_JNE, BPF_REG_2, SOCK_DGRAM, 3),
188
189                         /* sock->protocol == IPPROTO_ICMP */
190                         BPF_LDX_MEM(BPF_H, BPF_REG_2, BPF_REG_1,
191                                     offsetof(struct bpf_sock, protocol)),
192                         BPF_JMP_IMM(BPF_JNE, BPF_REG_2, IPPROTO_ICMP, 1),
193
194                         /* return 0 (block) */
195                         BPF_MOV64_IMM(BPF_REG_0, 0),
196                         BPF_EXIT_INSN(),
197                 },
198                 .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
199                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
200
201                 .domain = AF_INET,
202                 .type = SOCK_DGRAM,
203                 .protocol = IPPROTO_ICMP,
204
205                 .error = DENY_CREATE,
206         },
207         {
208                 .descr = "block AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6 socket",
209                 .insns = {
210                         BPF_MOV64_IMM(BPF_REG_0, 1),    /* r0 = verdict */
211
212                         /* sock->family == AF_INET6 */
213                         BPF_LDX_MEM(BPF_H, BPF_REG_2, BPF_REG_1,
214                                     offsetof(struct bpf_sock, family)),
215                         BPF_JMP_IMM(BPF_JNE, BPF_REG_2, AF_INET6, 5),
216
217                         /* sock->type == SOCK_DGRAM */
218                         BPF_LDX_MEM(BPF_H, BPF_REG_2, BPF_REG_1,
219                                     offsetof(struct bpf_sock, type)),
220                         BPF_JMP_IMM(BPF_JNE, BPF_REG_2, SOCK_DGRAM, 3),
221
222                         /* sock->protocol == IPPROTO_ICMPV6 */
223                         BPF_LDX_MEM(BPF_H, BPF_REG_2, BPF_REG_1,
224                                     offsetof(struct bpf_sock, protocol)),
225                         BPF_JMP_IMM(BPF_JNE, BPF_REG_2, IPPROTO_ICMPV6, 1),
226
227                         /* return 0 (block) */
228                         BPF_MOV64_IMM(BPF_REG_0, 0),
229                         BPF_EXIT_INSN(),
230                 },
231                 .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
232                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
233
234                 .domain = AF_INET,
235                 .type = SOCK_DGRAM,
236                 .protocol = IPPROTO_ICMPV6,
237
238                 .error = DENY_CREATE,
239         },
240         {
241                 .descr = "load w/o expected_attach_type (compat mode)",
242                 .insns = {
243                         /* return 1 */
244                         BPF_MOV64_IMM(BPF_REG_0, 1),
245                         BPF_EXIT_INSN(),
246                 },
247                 .expected_attach_type = 0,
248                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
249
250                 .domain = AF_INET,
251                 .type = SOCK_STREAM,
252         },
253 };
254
255 static int load_prog(const struct bpf_insn *insns,
256                      enum bpf_attach_type expected_attach_type)
257 {
258         LIBBPF_OPTS(bpf_prog_load_opts, opts,
259                     .expected_attach_type = expected_attach_type,
260                     .log_level = 2,
261                     .log_buf = bpf_log_buf,
262                     .log_size = sizeof(bpf_log_buf),
263         );
264         int fd, insns_cnt = 0;
265
266         for (;
267              insns[insns_cnt].code != (BPF_JMP | BPF_EXIT);
268              insns_cnt++) {
269         }
270         insns_cnt++;
271
272         fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns,
273                            insns_cnt, &opts);
274         if (verbose && fd < 0)
275                 fprintf(stderr, "%s\n", bpf_log_buf);
276
277         return fd;
278 }
279
280 static int run_test(int cgroup_fd, struct sock_create_test *test)
281 {
282         int sock_fd, err, prog_fd, optval, ret = -1;
283         socklen_t optlen = sizeof(optval);
284
285         prog_fd = load_prog(test->insns, test->expected_attach_type);
286         if (prog_fd < 0) {
287                 log_err("Failed to load BPF program");
288                 return -1;
289         }
290
291         err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0);
292         if (err < 0) {
293                 log_err("Failed to attach BPF program");
294                 goto close_prog_fd;
295         }
296
297         sock_fd = socket(test->domain, test->type, test->protocol);
298         if (sock_fd < 0) {
299                 if (test->error == DENY_CREATE)
300                         ret = 0;
301                 else
302                         log_err("Failed to create socket");
303
304                 goto detach_prog;
305         }
306
307         if (test->optname) {
308                 err = getsockopt(sock_fd, SOL_SOCKET, test->optname, &optval, &optlen);
309                 if (err) {
310                         log_err("Failed to call getsockopt");
311                         goto cleanup;
312                 }
313
314                 if (optval != test->optval) {
315                         errno = 0;
316                         log_err("getsockopt returned unexpected optval");
317                         goto cleanup;
318                 }
319         }
320
321         ret = test->error != OK;
322
323 cleanup:
324         close(sock_fd);
325 detach_prog:
326         bpf_prog_detach2(prog_fd, cgroup_fd, test->attach_type);
327 close_prog_fd:
328         close(prog_fd);
329         return ret;
330 }
331
332 void test_sock_create(void)
333 {
334         int cgroup_fd, i;
335
336         cgroup_fd = test__join_cgroup("/sock_create");
337         if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup"))
338                 return;
339
340         for (i = 0; i < ARRAY_SIZE(tests); i++) {
341                 if (!test__start_subtest(tests[i].descr))
342                         continue;
343
344                 ASSERT_OK(run_test(cgroup_fd, &tests[i]), tests[i].descr);
345         }
346
347         close(cgroup_fd);
348 }
This page took 0.04862 seconds and 4 git commands to generate.