Loading...
Note: File does not exist in v5.4.
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/bpf.h>
3#include <test_progs.h>
4#include "cgroup_helpers.h"
5
6static char bpf_log_buf[4096];
7static bool verbose;
8
9enum sock_create_test_error {
10 OK = 0,
11 DENY_CREATE,
12};
13
14static 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
255static 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
280static 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
323cleanup:
324 close(sock_fd);
325detach_prog:
326 bpf_prog_detach2(prog_fd, cgroup_fd, test->attach_type);
327close_prog_fd:
328 close(prog_fd);
329 return ret;
330}
331
332void 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}