1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/tcp.h>
3 #include <test_progs.h>
4 #include <io_uring/mini_liburing.h>
5 #include "cgroup_helpers.h"
6
7 static char bpf_log_buf[4096];
8 static bool verbose;
9
10 #ifndef PAGE_SIZE
11 #define PAGE_SIZE 4096
12 #endif
13
14 enum sockopt_test_error {
15 OK = 0,
16 DENY_LOAD,
17 DENY_ATTACH,
18 EOPNOTSUPP_GETSOCKOPT,
19 EPERM_GETSOCKOPT,
20 EFAULT_GETSOCKOPT,
21 EPERM_SETSOCKOPT,
22 EFAULT_SETSOCKOPT,
23 };
24
25 static struct sockopt_test {
26 const char *descr;
27 const struct bpf_insn insns[64];
28 enum bpf_prog_type prog_type;
29 enum bpf_attach_type attach_type;
30 enum bpf_attach_type expected_attach_type;
31
32 int set_optname;
33 int set_level;
34 const char set_optval[64];
35 socklen_t set_optlen;
36
37 int get_optname;
38 int get_level;
39 const char get_optval[64];
40 socklen_t get_optlen;
41 socklen_t get_optlen_ret;
42
43 enum sockopt_test_error error;
44 bool io_uring_support;
45 } tests[] = {
46
47 /* ==================== getsockopt ==================== */
48
49 {
50 .descr = "getsockopt: no expected_attach_type",
51 .insns = {
52 /* return 1 */
53 BPF_MOV64_IMM(BPF_REG_0, 1),
54 BPF_EXIT_INSN(),
55
56 },
57 .attach_type = BPF_CGROUP_GETSOCKOPT,
58 .expected_attach_type = 0,
59 .error = DENY_LOAD,
60 },
61 {
62 .descr = "getsockopt: wrong expected_attach_type",
63 .insns = {
64 /* return 1 */
65 BPF_MOV64_IMM(BPF_REG_0, 1),
66 BPF_EXIT_INSN(),
67
68 },
69 .attach_type = BPF_CGROUP_GETSOCKOPT,
70 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
71 .error = DENY_ATTACH,
72 },
73 {
74 .descr = "getsockopt: bypass bpf hook",
75 .insns = {
76 /* return 1 */
77 BPF_MOV64_IMM(BPF_REG_0, 1),
78 BPF_EXIT_INSN(),
79 },
80 .attach_type = BPF_CGROUP_GETSOCKOPT,
81 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
82
83 .get_level = SOL_IP,
84 .set_level = SOL_IP,
85
86 .get_optname = IP_TOS,
87 .set_optname = IP_TOS,
88
89 .set_optval = { 1 << 3 },
90 .set_optlen = 1,
91
92 .get_optval = { 1 << 3 },
93 .get_optlen = 1,
94 },
95 {
96 .descr = "getsockopt: return EPERM from bpf hook",
97 .insns = {
98 BPF_MOV64_IMM(BPF_REG_0, 0),
99 BPF_EXIT_INSN(),
100 },
101 .attach_type = BPF_CGROUP_GETSOCKOPT,
102 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
103
104 .get_level = SOL_IP,
105 .get_optname = IP_TOS,
106
107 .get_optlen = 1,
108 .error = EPERM_GETSOCKOPT,
109 },
110 {
111 .descr = "getsockopt: no optval bounds check, deny loading",
112 .insns = {
113 /* r6 = ctx->optval */
114 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
115 offsetof(struct bpf_sockopt, optval)),
116
117 /* ctx->optval[0] = 0x80 */
118 BPF_MOV64_IMM(BPF_REG_0, 0x80),
119 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_0, 0),
120
121 /* return 1 */
122 BPF_MOV64_IMM(BPF_REG_0, 1),
123 BPF_EXIT_INSN(),
124 },
125 .attach_type = BPF_CGROUP_GETSOCKOPT,
126 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
127 .error = DENY_LOAD,
128 },
129 {
130 .descr = "getsockopt: read ctx->level",
131 .insns = {
132 /* r6 = ctx->level */
133 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
134 offsetof(struct bpf_sockopt, level)),
135
136 /* if (ctx->level == 123) { */
137 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
138 /* ctx->retval = 0 */
139 BPF_MOV64_IMM(BPF_REG_0, 0),
140 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
141 offsetof(struct bpf_sockopt, retval)),
142 /* return 1 */
143 BPF_MOV64_IMM(BPF_REG_0, 1),
144 BPF_JMP_A(1),
145 /* } else { */
146 /* return 0 */
147 BPF_MOV64_IMM(BPF_REG_0, 0),
148 /* } */
149 BPF_EXIT_INSN(),
150 },
151 .attach_type = BPF_CGROUP_GETSOCKOPT,
152 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
153
154 .get_level = 123,
155
156 .get_optlen = 1,
157 },
158 {
159 .descr = "getsockopt: deny writing to ctx->level",
160 .insns = {
161 /* ctx->level = 1 */
162 BPF_MOV64_IMM(BPF_REG_0, 1),
163 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
164 offsetof(struct bpf_sockopt, level)),
165 BPF_EXIT_INSN(),
166 },
167 .attach_type = BPF_CGROUP_GETSOCKOPT,
168 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
169
170 .error = DENY_LOAD,
171 },
172 {
173 .descr = "getsockopt: read ctx->optname",
174 .insns = {
175 /* r6 = ctx->optname */
176 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
177 offsetof(struct bpf_sockopt, optname)),
178
179 /* if (ctx->optname == 123) { */
180 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
181 /* ctx->retval = 0 */
182 BPF_MOV64_IMM(BPF_REG_0, 0),
183 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
184 offsetof(struct bpf_sockopt, retval)),
185 /* return 1 */
186 BPF_MOV64_IMM(BPF_REG_0, 1),
187 BPF_JMP_A(1),
188 /* } else { */
189 /* return 0 */
190 BPF_MOV64_IMM(BPF_REG_0, 0),
191 /* } */
192 BPF_EXIT_INSN(),
193 },
194 .attach_type = BPF_CGROUP_GETSOCKOPT,
195 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
196
197 .get_optname = 123,
198
199 .get_optlen = 1,
200 },
201 {
202 .descr = "getsockopt: read ctx->retval",
203 .insns = {
204 /* r6 = ctx->retval */
205 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
206 offsetof(struct bpf_sockopt, retval)),
207
208 /* return 1 */
209 BPF_MOV64_IMM(BPF_REG_0, 1),
210 BPF_EXIT_INSN(),
211 },
212 .attach_type = BPF_CGROUP_GETSOCKOPT,
213 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
214
215 .get_level = SOL_IP,
216 .get_optname = IP_TOS,
217 .get_optlen = 1,
218 },
219 {
220 .descr = "getsockopt: deny writing to ctx->optname",
221 .insns = {
222 /* ctx->optname = 1 */
223 BPF_MOV64_IMM(BPF_REG_0, 1),
224 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
225 offsetof(struct bpf_sockopt, optname)),
226 BPF_EXIT_INSN(),
227 },
228 .attach_type = BPF_CGROUP_GETSOCKOPT,
229 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
230
231 .error = DENY_LOAD,
232 },
233 {
234 .descr = "getsockopt: read ctx->optlen",
235 .insns = {
236 /* r6 = ctx->optlen */
237 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
238 offsetof(struct bpf_sockopt, optlen)),
239
240 /* if (ctx->optlen == 64) { */
241 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4),
242 /* ctx->retval = 0 */
243 BPF_MOV64_IMM(BPF_REG_0, 0),
244 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
245 offsetof(struct bpf_sockopt, retval)),
246 /* return 1 */
247 BPF_MOV64_IMM(BPF_REG_0, 1),
248 BPF_JMP_A(1),
249 /* } else { */
250 /* return 0 */
251 BPF_MOV64_IMM(BPF_REG_0, 0),
252 /* } */
253 BPF_EXIT_INSN(),
254 },
255 .attach_type = BPF_CGROUP_GETSOCKOPT,
256 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
257
258 .get_level = SOL_SOCKET,
259 .get_optlen = 64,
260 .io_uring_support = true,
261 },
262 {
263 .descr = "getsockopt: deny bigger ctx->optlen",
264 .insns = {
265 /* ctx->optlen = 65 */
266 BPF_MOV64_IMM(BPF_REG_0, 65),
267 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
268 offsetof(struct bpf_sockopt, optlen)),
269
270 /* ctx->retval = 0 */
271 BPF_MOV64_IMM(BPF_REG_0, 0),
272 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
273 offsetof(struct bpf_sockopt, retval)),
274
275 /* return 1 */
276 BPF_MOV64_IMM(BPF_REG_0, 1),
277 BPF_EXIT_INSN(),
278 },
279 .attach_type = BPF_CGROUP_GETSOCKOPT,
280 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
281
282 .get_optlen = 64,
283
284 .error = EFAULT_GETSOCKOPT,
285 .io_uring_support = true,
286 },
287 {
288 .descr = "getsockopt: deny negative ctx->optlen in TCP_ZEROCOPY_RECEIVE",
289 .insns = {
290 /* ctx->optlen = -1 */
291 BPF_MOV64_IMM(BPF_REG_0, -1),
292 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
293 offsetof(struct bpf_sockopt, optlen)),
294
295 /* return 1 */
296 BPF_MOV64_IMM(BPF_REG_0, 1),
297 BPF_EXIT_INSN(),
298 },
299 .attach_type = BPF_CGROUP_GETSOCKOPT,
300 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
301
302 .get_level = IPPROTO_TCP,
303 .get_optname = TCP_ZEROCOPY_RECEIVE,
304 .get_optlen = sizeof(struct tcp_zerocopy_receive),
305
306 .error = EFAULT_GETSOCKOPT,
307 },
308 {
309 .descr = "getsockopt: ignore >PAGE_SIZE optlen",
310 .insns = {
311 /* write 0xFF to the first optval byte */
312
313 /* r6 = ctx->optval */
314 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
315 offsetof(struct bpf_sockopt, optval)),
316 /* r2 = ctx->optval */
317 BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
318 /* r6 = ctx->optval + 1 */
319 BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),
320
321 /* r7 = ctx->optval_end */
322 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,
323 offsetof(struct bpf_sockopt, optval_end)),
324
325 /* if (ctx->optval + 1 <= ctx->optval_end) { */
326 BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),
327 /* ctx->optval[0] = 0xF0 */
328 BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xFF),
329 /* } */
330
331 /* retval changes are ignored */
332 /* ctx->retval = 5 */
333 BPF_MOV64_IMM(BPF_REG_0, 5),
334 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
335 offsetof(struct bpf_sockopt, retval)),
336
337 /* return 1 */
338 BPF_MOV64_IMM(BPF_REG_0, 1),
339 BPF_EXIT_INSN(),
340 },
341 .attach_type = BPF_CGROUP_GETSOCKOPT,
342 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
343
344 .get_level = 1234,
345 .get_optname = 5678,
346 .get_optval = {}, /* the changes are ignored */
347 .get_optlen = PAGE_SIZE + 1,
348 .error = EOPNOTSUPP_GETSOCKOPT,
349 .io_uring_support = true,
350 },
351 {
352 .descr = "getsockopt: support smaller ctx->optlen",
353 .insns = {
354 /* ctx->optlen = 32 */
355 BPF_MOV64_IMM(BPF_REG_0, 32),
356 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
357 offsetof(struct bpf_sockopt, optlen)),
358 /* ctx->retval = 0 */
359 BPF_MOV64_IMM(BPF_REG_0, 0),
360 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
361 offsetof(struct bpf_sockopt, retval)),
362 /* return 1 */
363 BPF_MOV64_IMM(BPF_REG_0, 1),
364 BPF_EXIT_INSN(),
365 },
366 .attach_type = BPF_CGROUP_GETSOCKOPT,
367 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
368
369 .get_level = SOL_SOCKET,
370 .get_optlen = 64,
371 .get_optlen_ret = 32,
372 .io_uring_support = true,
373 },
374 {
375 .descr = "getsockopt: deny writing to ctx->optval",
376 .insns = {
377 /* ctx->optval = 1 */
378 BPF_MOV64_IMM(BPF_REG_0, 1),
379 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
380 offsetof(struct bpf_sockopt, optval)),
381 BPF_EXIT_INSN(),
382 },
383 .attach_type = BPF_CGROUP_GETSOCKOPT,
384 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
385
386 .error = DENY_LOAD,
387 },
388 {
389 .descr = "getsockopt: deny writing to ctx->optval_end",
390 .insns = {
391 /* ctx->optval_end = 1 */
392 BPF_MOV64_IMM(BPF_REG_0, 1),
393 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
394 offsetof(struct bpf_sockopt, optval_end)),
395 BPF_EXIT_INSN(),
396 },
397 .attach_type = BPF_CGROUP_GETSOCKOPT,
398 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
399
400 .error = DENY_LOAD,
401 },
402 {
403 .descr = "getsockopt: rewrite value",
404 .insns = {
405 /* r6 = ctx->optval */
406 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
407 offsetof(struct bpf_sockopt, optval)),
408 /* r2 = ctx->optval */
409 BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
410 /* r6 = ctx->optval + 1 */
411 BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),
412
413 /* r7 = ctx->optval_end */
414 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,
415 offsetof(struct bpf_sockopt, optval_end)),
416
417 /* if (ctx->optval + 1 <= ctx->optval_end) { */
418 BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),
419 /* ctx->optval[0] = 0xF0 */
420 BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0),
421 /* } */
422
423 /* ctx->retval = 0 */
424 BPF_MOV64_IMM(BPF_REG_0, 0),
425 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
426 offsetof(struct bpf_sockopt, retval)),
427
428 /* return 1*/
429 BPF_MOV64_IMM(BPF_REG_0, 1),
430 BPF_EXIT_INSN(),
431 },
432 .attach_type = BPF_CGROUP_GETSOCKOPT,
433 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
434
435 .get_level = SOL_IP,
436 .get_optname = IP_TOS,
437
438 .get_optval = { 0xF0 },
439 .get_optlen = 1,
440 },
441
442 /* ==================== setsockopt ==================== */
443
444 {
445 .descr = "setsockopt: no expected_attach_type",
446 .insns = {
447 /* return 1 */
448 BPF_MOV64_IMM(BPF_REG_0, 1),
449 BPF_EXIT_INSN(),
450
451 },
452 .attach_type = BPF_CGROUP_SETSOCKOPT,
453 .expected_attach_type = 0,
454 .error = DENY_LOAD,
455 },
456 {
457 .descr = "setsockopt: wrong expected_attach_type",
458 .insns = {
459 /* return 1 */
460 BPF_MOV64_IMM(BPF_REG_0, 1),
461 BPF_EXIT_INSN(),
462
463 },
464 .attach_type = BPF_CGROUP_SETSOCKOPT,
465 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
466 .error = DENY_ATTACH,
467 },
468 {
469 .descr = "setsockopt: bypass bpf hook",
470 .insns = {
471 /* return 1 */
472 BPF_MOV64_IMM(BPF_REG_0, 1),
473 BPF_EXIT_INSN(),
474 },
475 .attach_type = BPF_CGROUP_SETSOCKOPT,
476 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
477
478 .get_level = SOL_IP,
479 .set_level = SOL_IP,
480
481 .get_optname = IP_TOS,
482 .set_optname = IP_TOS,
483
484 .set_optval = { 1 << 3 },
485 .set_optlen = 1,
486
487 .get_optval = { 1 << 3 },
488 .get_optlen = 1,
489 },
490 {
491 .descr = "setsockopt: return EPERM from bpf hook",
492 .insns = {
493 /* return 0 */
494 BPF_MOV64_IMM(BPF_REG_0, 0),
495 BPF_EXIT_INSN(),
496 },
497 .attach_type = BPF_CGROUP_SETSOCKOPT,
498 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
499
500 .set_level = SOL_IP,
501 .set_optname = IP_TOS,
502
503 .set_optlen = 1,
504 .error = EPERM_SETSOCKOPT,
505 },
506 {
507 .descr = "setsockopt: no optval bounds check, deny loading",
508 .insns = {
509 /* r6 = ctx->optval */
510 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
511 offsetof(struct bpf_sockopt, optval)),
512
513 /* r0 = ctx->optval[0] */
514 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6, 0),
515
516 /* return 1 */
517 BPF_MOV64_IMM(BPF_REG_0, 1),
518 BPF_EXIT_INSN(),
519 },
520 .attach_type = BPF_CGROUP_SETSOCKOPT,
521 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
522 .error = DENY_LOAD,
523 },
524 {
525 .descr = "setsockopt: read ctx->level",
526 .insns = {
527 /* r6 = ctx->level */
528 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
529 offsetof(struct bpf_sockopt, level)),
530
531 /* if (ctx->level == 123) { */
532 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
533 /* ctx->optlen = -1 */
534 BPF_MOV64_IMM(BPF_REG_0, -1),
535 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
536 offsetof(struct bpf_sockopt, optlen)),
537 /* return 1 */
538 BPF_MOV64_IMM(BPF_REG_0, 1),
539 BPF_JMP_A(1),
540 /* } else { */
541 /* return 0 */
542 BPF_MOV64_IMM(BPF_REG_0, 0),
543 /* } */
544 BPF_EXIT_INSN(),
545 },
546 .attach_type = BPF_CGROUP_SETSOCKOPT,
547 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
548
549 .set_level = 123,
550
551 .set_optlen = 1,
552 .io_uring_support = true,
553 },
554 {
555 .descr = "setsockopt: allow changing ctx->level",
556 .insns = {
557 /* ctx->level = SOL_IP */
558 BPF_MOV64_IMM(BPF_REG_0, SOL_IP),
559 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
560 offsetof(struct bpf_sockopt, level)),
561 /* return 1 */
562 BPF_MOV64_IMM(BPF_REG_0, 1),
563 BPF_EXIT_INSN(),
564 },
565 .attach_type = BPF_CGROUP_SETSOCKOPT,
566 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
567
568 .get_level = SOL_IP,
569 .set_level = 234, /* should be rewritten to SOL_IP */
570
571 .get_optname = IP_TOS,
572 .set_optname = IP_TOS,
573
574 .set_optval = { 1 << 3 },
575 .set_optlen = 1,
576 .get_optval = { 1 << 3 },
577 .get_optlen = 1,
578 },
579 {
580 .descr = "setsockopt: read ctx->optname",
581 .insns = {
582 /* r6 = ctx->optname */
583 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
584 offsetof(struct bpf_sockopt, optname)),
585
586 /* if (ctx->optname == 123) { */
587 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
588 /* ctx->optlen = -1 */
589 BPF_MOV64_IMM(BPF_REG_0, -1),
590 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
591 offsetof(struct bpf_sockopt, optlen)),
592 /* return 1 */
593 BPF_MOV64_IMM(BPF_REG_0, 1),
594 BPF_JMP_A(1),
595 /* } else { */
596 /* return 0 */
597 BPF_MOV64_IMM(BPF_REG_0, 0),
598 /* } */
599 BPF_EXIT_INSN(),
600 },
601 .attach_type = BPF_CGROUP_SETSOCKOPT,
602 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
603
604 .set_optname = 123,
605
606 .set_optlen = 1,
607 .io_uring_support = true,
608 },
609 {
610 .descr = "setsockopt: allow changing ctx->optname",
611 .insns = {
612 /* ctx->optname = IP_TOS */
613 BPF_MOV64_IMM(BPF_REG_0, IP_TOS),
614 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
615 offsetof(struct bpf_sockopt, optname)),
616 /* return 1 */
617 BPF_MOV64_IMM(BPF_REG_0, 1),
618 BPF_EXIT_INSN(),
619 },
620 .attach_type = BPF_CGROUP_SETSOCKOPT,
621 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
622
623 .get_level = SOL_IP,
624 .set_level = SOL_IP,
625
626 .get_optname = IP_TOS,
627 .set_optname = 456, /* should be rewritten to IP_TOS */
628
629 .set_optval = { 1 << 3 },
630 .set_optlen = 1,
631 .get_optval = { 1 << 3 },
632 .get_optlen = 1,
633 },
634 {
635 .descr = "setsockopt: read ctx->optlen",
636 .insns = {
637 /* r6 = ctx->optlen */
638 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
639 offsetof(struct bpf_sockopt, optlen)),
640
641 /* if (ctx->optlen == 64) { */
642 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4),
643 /* ctx->optlen = -1 */
644 BPF_MOV64_IMM(BPF_REG_0, -1),
645 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
646 offsetof(struct bpf_sockopt, optlen)),
647 /* return 1 */
648 BPF_MOV64_IMM(BPF_REG_0, 1),
649 BPF_JMP_A(1),
650 /* } else { */
651 /* return 0 */
652 BPF_MOV64_IMM(BPF_REG_0, 0),
653 /* } */
654 BPF_EXIT_INSN(),
655 },
656 .attach_type = BPF_CGROUP_SETSOCKOPT,
657 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
658
659 .set_optlen = 64,
660 .io_uring_support = true,
661 },
662 {
663 .descr = "setsockopt: ctx->optlen == -1 is ok",
664 .insns = {
665 /* ctx->optlen = -1 */
666 BPF_MOV64_IMM(BPF_REG_0, -1),
667 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
668 offsetof(struct bpf_sockopt, optlen)),
669 /* return 1 */
670 BPF_MOV64_IMM(BPF_REG_0, 1),
671 BPF_EXIT_INSN(),
672 },
673 .attach_type = BPF_CGROUP_SETSOCKOPT,
674 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
675
676 .set_optlen = 64,
677 .io_uring_support = true,
678 },
679 {
680 .descr = "setsockopt: deny ctx->optlen < 0 (except -1)",
681 .insns = {
682 /* ctx->optlen = -2 */
683 BPF_MOV64_IMM(BPF_REG_0, -2),
684 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
685 offsetof(struct bpf_sockopt, optlen)),
686 /* return 1 */
687 BPF_MOV64_IMM(BPF_REG_0, 1),
688 BPF_EXIT_INSN(),
689 },
690 .attach_type = BPF_CGROUP_SETSOCKOPT,
691 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
692
693 .set_optlen = 4,
694
695 .error = EFAULT_SETSOCKOPT,
696 .io_uring_support = true,
697 },
698 {
699 .descr = "setsockopt: deny ctx->optlen > input optlen",
700 .insns = {
701 /* ctx->optlen = 65 */
702 BPF_MOV64_IMM(BPF_REG_0, 65),
703 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
704 offsetof(struct bpf_sockopt, optlen)),
705 BPF_MOV64_IMM(BPF_REG_0, 1),
706 BPF_EXIT_INSN(),
707 },
708 .attach_type = BPF_CGROUP_SETSOCKOPT,
709 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
710
711 .set_optlen = 64,
712
713 .error = EFAULT_SETSOCKOPT,
714 .io_uring_support = true,
715 },
716 {
717 .descr = "setsockopt: ignore >PAGE_SIZE optlen",
718 .insns = {
719 /* write 0xFF to the first optval byte */
720
721 /* r6 = ctx->optval */
722 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
723 offsetof(struct bpf_sockopt, optval)),
724 /* r2 = ctx->optval */
725 BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
726 /* r6 = ctx->optval + 1 */
727 BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),
728
729 /* r7 = ctx->optval_end */
730 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,
731 offsetof(struct bpf_sockopt, optval_end)),
732
733 /* if (ctx->optval + 1 <= ctx->optval_end) { */
734 BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),
735 /* ctx->optval[0] = 0xF0 */
736 BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0),
737 /* } */
738
739 BPF_MOV64_IMM(BPF_REG_0, 1),
740 BPF_EXIT_INSN(),
741 },
742 .attach_type = BPF_CGROUP_SETSOCKOPT,
743 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
744
745 .set_level = SOL_IP,
746 .set_optname = IP_TOS,
747 .set_optval = {},
748 .set_optlen = PAGE_SIZE + 1,
749
750 .get_level = SOL_IP,
751 .get_optname = IP_TOS,
752 .get_optval = {}, /* the changes are ignored */
753 .get_optlen = 4,
754 },
755 {
756 .descr = "setsockopt: allow changing ctx->optlen within bounds",
757 .insns = {
758 /* r6 = ctx->optval */
759 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
760 offsetof(struct bpf_sockopt, optval)),
761 /* r2 = ctx->optval */
762 BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
763 /* r6 = ctx->optval + 1 */
764 BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),
765
766 /* r7 = ctx->optval_end */
767 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,
768 offsetof(struct bpf_sockopt, optval_end)),
769
770 /* if (ctx->optval + 1 <= ctx->optval_end) { */
771 BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),
772 /* ctx->optval[0] = 1 << 3 */
773 BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 1 << 3),
774 /* } */
775
776 /* ctx->optlen = 1 */
777 BPF_MOV64_IMM(BPF_REG_0, 1),
778 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
779 offsetof(struct bpf_sockopt, optlen)),
780
781 /* return 1*/
782 BPF_MOV64_IMM(BPF_REG_0, 1),
783 BPF_EXIT_INSN(),
784 },
785 .attach_type = BPF_CGROUP_SETSOCKOPT,
786 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
787
788 .get_level = SOL_IP,
789 .set_level = SOL_IP,
790
791 .get_optname = IP_TOS,
792 .set_optname = IP_TOS,
793
794 .set_optval = { 1, 1, 1, 1 },
795 .set_optlen = 4,
796 .get_optval = { 1 << 3 },
797 .get_optlen = 1,
798 },
799 {
800 .descr = "setsockopt: deny write ctx->retval",
801 .insns = {
802 /* ctx->retval = 0 */
803 BPF_MOV64_IMM(BPF_REG_0, 0),
804 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
805 offsetof(struct bpf_sockopt, retval)),
806
807 /* return 1 */
808 BPF_MOV64_IMM(BPF_REG_0, 1),
809 BPF_EXIT_INSN(),
810 },
811 .attach_type = BPF_CGROUP_SETSOCKOPT,
812 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
813
814 .error = DENY_LOAD,
815 },
816 {
817 .descr = "setsockopt: deny read ctx->retval",
818 .insns = {
819 /* r6 = ctx->retval */
820 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
821 offsetof(struct bpf_sockopt, retval)),
822
823 /* return 1 */
824 BPF_MOV64_IMM(BPF_REG_0, 1),
825 BPF_EXIT_INSN(),
826 },
827 .attach_type = BPF_CGROUP_SETSOCKOPT,
828 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
829
830 .error = DENY_LOAD,
831 },
832 {
833 .descr = "setsockopt: deny writing to ctx->optval",
834 .insns = {
835 /* ctx->optval = 1 */
836 BPF_MOV64_IMM(BPF_REG_0, 1),
837 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
838 offsetof(struct bpf_sockopt, optval)),
839 BPF_EXIT_INSN(),
840 },
841 .attach_type = BPF_CGROUP_SETSOCKOPT,
842 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
843
844 .error = DENY_LOAD,
845 },
846 {
847 .descr = "setsockopt: deny writing to ctx->optval_end",
848 .insns = {
849 /* ctx->optval_end = 1 */
850 BPF_MOV64_IMM(BPF_REG_0, 1),
851 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
852 offsetof(struct bpf_sockopt, optval_end)),
853 BPF_EXIT_INSN(),
854 },
855 .attach_type = BPF_CGROUP_SETSOCKOPT,
856 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
857
858 .error = DENY_LOAD,
859 },
860 {
861 .descr = "setsockopt: allow IP_TOS <= 128",
862 .insns = {
863 /* r6 = ctx->optval */
864 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
865 offsetof(struct bpf_sockopt, optval)),
866 /* r7 = ctx->optval + 1 */
867 BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
868 BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
869
870 /* r8 = ctx->optval_end */
871 BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1,
872 offsetof(struct bpf_sockopt, optval_end)),
873
874 /* if (ctx->optval + 1 <= ctx->optval_end) { */
875 BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4),
876
877 /* r9 = ctx->optval[0] */
878 BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0),
879
880 /* if (ctx->optval[0] < 128) */
881 BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2),
882 BPF_MOV64_IMM(BPF_REG_0, 1),
883 BPF_JMP_A(1),
884 /* } */
885
886 /* } else { */
887 BPF_MOV64_IMM(BPF_REG_0, 0),
888 /* } */
889
890 BPF_EXIT_INSN(),
891 },
892 .attach_type = BPF_CGROUP_SETSOCKOPT,
893 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
894
895 .get_level = SOL_IP,
896 .set_level = SOL_IP,
897
898 .get_optname = IP_TOS,
899 .set_optname = IP_TOS,
900
901 .set_optval = { 0x80 },
902 .set_optlen = 1,
903 .get_optval = { 0x80 },
904 .get_optlen = 1,
905 },
906 {
907 .descr = "setsockopt: deny IP_TOS > 128",
908 .insns = {
909 /* r6 = ctx->optval */
910 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
911 offsetof(struct bpf_sockopt, optval)),
912 /* r7 = ctx->optval + 1 */
913 BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
914 BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
915
916 /* r8 = ctx->optval_end */
917 BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1,
918 offsetof(struct bpf_sockopt, optval_end)),
919
920 /* if (ctx->optval + 1 <= ctx->optval_end) { */
921 BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4),
922
923 /* r9 = ctx->optval[0] */
924 BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0),
925
926 /* if (ctx->optval[0] < 128) */
927 BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2),
928 BPF_MOV64_IMM(BPF_REG_0, 1),
929 BPF_JMP_A(1),
930 /* } */
931
932 /* } else { */
933 BPF_MOV64_IMM(BPF_REG_0, 0),
934 /* } */
935
936 BPF_EXIT_INSN(),
937 },
938 .attach_type = BPF_CGROUP_SETSOCKOPT,
939 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
940
941 .get_level = SOL_IP,
942 .set_level = SOL_IP,
943
944 .get_optname = IP_TOS,
945 .set_optname = IP_TOS,
946
947 .set_optval = { 0x81 },
948 .set_optlen = 1,
949 .get_optval = { 0x00 },
950 .get_optlen = 1,
951
952 .error = EPERM_SETSOCKOPT,
953 },
954
955 /* ==================== prog_type ==================== */
956
957 {
958 .descr = "can attach only BPF_CGROUP_SETSOCKOP",
959 .insns = {
960 /* return 1 */
961 BPF_MOV64_IMM(BPF_REG_0, 1),
962 BPF_EXIT_INSN(),
963
964 },
965 .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
966 .attach_type = BPF_CGROUP_SETSOCKOPT,
967 .expected_attach_type = 0,
968 .error = DENY_ATTACH,
969 },
970
971 {
972 .descr = "can attach only BPF_CGROUP_GETSOCKOP",
973 .insns = {
974 /* return 1 */
975 BPF_MOV64_IMM(BPF_REG_0, 1),
976 BPF_EXIT_INSN(),
977
978 },
979 .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
980 .attach_type = BPF_CGROUP_GETSOCKOPT,
981 .expected_attach_type = 0,
982 .error = DENY_ATTACH,
983 },
984 };
985
load_prog(const struct bpf_insn * insns,enum bpf_prog_type prog_type,enum bpf_attach_type expected_attach_type)986 static int load_prog(const struct bpf_insn *insns,
987 enum bpf_prog_type prog_type,
988 enum bpf_attach_type expected_attach_type)
989 {
990 LIBBPF_OPTS(bpf_prog_load_opts, opts,
991 .expected_attach_type = expected_attach_type,
992 .log_level = 2,
993 .log_buf = bpf_log_buf,
994 .log_size = sizeof(bpf_log_buf),
995 );
996 int fd, insns_cnt = 0;
997
998 for (;
999 insns[insns_cnt].code != (BPF_JMP | BPF_EXIT);
1000 insns_cnt++) {
1001 }
1002 insns_cnt++;
1003
1004 fd = bpf_prog_load(prog_type, NULL, "GPL", insns, insns_cnt, &opts);
1005 if (verbose && fd < 0)
1006 fprintf(stderr, "%s\n", bpf_log_buf);
1007
1008 return fd;
1009 }
1010
1011 /* Core function that handles io_uring ring initialization,
1012 * sending SQE with sockopt command and waiting for the CQE.
1013 */
uring_sockopt(int op,int fd,int level,int optname,const void * optval,socklen_t optlen)1014 static int uring_sockopt(int op, int fd, int level, int optname,
1015 const void *optval, socklen_t optlen)
1016 {
1017 struct io_uring_cqe *cqe;
1018 struct io_uring_sqe *sqe;
1019 struct io_uring ring;
1020 int err;
1021
1022 err = io_uring_queue_init(1, &ring, 0);
1023 if (!ASSERT_OK(err, "io_uring initialization"))
1024 return err;
1025
1026 sqe = io_uring_get_sqe(&ring);
1027 if (!ASSERT_NEQ(sqe, NULL, "Get an SQE")) {
1028 err = -1;
1029 goto fail;
1030 }
1031
1032 io_uring_prep_cmd(sqe, op, fd, level, optname, optval, optlen);
1033
1034 err = io_uring_submit(&ring);
1035 if (!ASSERT_EQ(err, 1, "Submit SQE"))
1036 goto fail;
1037
1038 err = io_uring_wait_cqe(&ring, &cqe);
1039 if (!ASSERT_OK(err, "Wait for CQE"))
1040 goto fail;
1041
1042 err = cqe->res;
1043
1044 fail:
1045 io_uring_queue_exit(&ring);
1046
1047 return err;
1048 }
1049
uring_setsockopt(int fd,int level,int optname,const void * optval,socklen_t optlen)1050 static int uring_setsockopt(int fd, int level, int optname, const void *optval,
1051 socklen_t optlen)
1052 {
1053 return uring_sockopt(SOCKET_URING_OP_SETSOCKOPT, fd, level, optname,
1054 optval, optlen);
1055 }
1056
uring_getsockopt(int fd,int level,int optname,void * optval,socklen_t * optlen)1057 static int uring_getsockopt(int fd, int level, int optname, void *optval,
1058 socklen_t *optlen)
1059 {
1060 int ret = uring_sockopt(SOCKET_URING_OP_GETSOCKOPT, fd, level, optname,
1061 optval, *optlen);
1062 if (ret < 0)
1063 return ret;
1064
1065 /* Populate optlen back to be compatible with systemcall interface,
1066 * and simplify the test.
1067 */
1068 *optlen = ret;
1069
1070 return 0;
1071 }
1072
1073 /* Execute the setsocktopt operation */
call_setsockopt(bool use_io_uring,int fd,int level,int optname,const void * optval,socklen_t optlen)1074 static int call_setsockopt(bool use_io_uring, int fd, int level, int optname,
1075 const void *optval, socklen_t optlen)
1076 {
1077 if (use_io_uring)
1078 return uring_setsockopt(fd, level, optname, optval, optlen);
1079
1080 return setsockopt(fd, level, optname, optval, optlen);
1081 }
1082
1083 /* Execute the getsocktopt operation */
call_getsockopt(bool use_io_uring,int fd,int level,int optname,void * optval,socklen_t * optlen)1084 static int call_getsockopt(bool use_io_uring, int fd, int level, int optname,
1085 void *optval, socklen_t *optlen)
1086 {
1087 if (use_io_uring)
1088 return uring_getsockopt(fd, level, optname, optval, optlen);
1089
1090 return getsockopt(fd, level, optname, optval, optlen);
1091 }
1092
run_test(int cgroup_fd,struct sockopt_test * test,bool use_io_uring,bool use_link)1093 static int run_test(int cgroup_fd, struct sockopt_test *test, bool use_io_uring,
1094 bool use_link)
1095 {
1096 int prog_type = BPF_PROG_TYPE_CGROUP_SOCKOPT;
1097 int sock_fd, err, prog_fd, link_fd = -1;
1098 void *optval = NULL;
1099 int ret = 0;
1100
1101 if (test->prog_type)
1102 prog_type = test->prog_type;
1103
1104 prog_fd = load_prog(test->insns, prog_type, test->expected_attach_type);
1105 if (prog_fd < 0) {
1106 if (test->error == DENY_LOAD)
1107 return 0;
1108
1109 log_err("Failed to load BPF program");
1110 return -1;
1111 }
1112
1113 if (use_link) {
1114 err = bpf_link_create(prog_fd, cgroup_fd, test->attach_type, NULL);
1115 link_fd = err;
1116 } else {
1117 err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0);
1118 }
1119 if (err < 0) {
1120 if (test->error == DENY_ATTACH)
1121 goto close_prog_fd;
1122
1123 log_err("Failed to attach BPF program");
1124 ret = -1;
1125 goto close_prog_fd;
1126 }
1127
1128 sock_fd = socket(AF_INET, SOCK_STREAM, 0);
1129 if (sock_fd < 0) {
1130 log_err("Failed to create AF_INET socket");
1131 ret = -1;
1132 goto detach_prog;
1133 }
1134
1135 if (test->set_optlen) {
1136 if (test->set_optlen >= PAGE_SIZE) {
1137 int num_pages = test->set_optlen / PAGE_SIZE;
1138 int remainder = test->set_optlen % PAGE_SIZE;
1139
1140 test->set_optlen = num_pages * sysconf(_SC_PAGESIZE) + remainder;
1141 }
1142
1143 err = call_setsockopt(use_io_uring, sock_fd, test->set_level,
1144 test->set_optname, test->set_optval,
1145 test->set_optlen);
1146 if (err) {
1147 if (errno == EPERM && test->error == EPERM_SETSOCKOPT)
1148 goto close_sock_fd;
1149 if (errno == EFAULT && test->error == EFAULT_SETSOCKOPT)
1150 goto free_optval;
1151
1152 log_err("Failed to call setsockopt");
1153 ret = -1;
1154 goto close_sock_fd;
1155 }
1156 }
1157
1158 if (test->get_optlen) {
1159 if (test->get_optlen >= PAGE_SIZE) {
1160 int num_pages = test->get_optlen / PAGE_SIZE;
1161 int remainder = test->get_optlen % PAGE_SIZE;
1162
1163 test->get_optlen = num_pages * sysconf(_SC_PAGESIZE) + remainder;
1164 }
1165
1166 optval = malloc(test->get_optlen);
1167 memset(optval, 0, test->get_optlen);
1168 socklen_t optlen = test->get_optlen;
1169 socklen_t expected_get_optlen = test->get_optlen_ret ?:
1170 test->get_optlen;
1171
1172 err = call_getsockopt(use_io_uring, sock_fd, test->get_level,
1173 test->get_optname, optval, &optlen);
1174 if (err) {
1175 if (errno == EOPNOTSUPP && test->error == EOPNOTSUPP_GETSOCKOPT)
1176 goto free_optval;
1177 if (errno == EPERM && test->error == EPERM_GETSOCKOPT)
1178 goto free_optval;
1179 if (errno == EFAULT && test->error == EFAULT_GETSOCKOPT)
1180 goto free_optval;
1181
1182 log_err("Failed to call getsockopt");
1183 ret = -1;
1184 goto free_optval;
1185 }
1186
1187 if (optlen != expected_get_optlen) {
1188 errno = 0;
1189 log_err("getsockopt returned unexpected optlen");
1190 ret = -1;
1191 goto free_optval;
1192 }
1193
1194 if (memcmp(optval, test->get_optval, optlen) != 0) {
1195 errno = 0;
1196 log_err("getsockopt returned unexpected optval");
1197 ret = -1;
1198 goto free_optval;
1199 }
1200 }
1201
1202 ret = test->error != OK;
1203
1204 free_optval:
1205 free(optval);
1206 close_sock_fd:
1207 close(sock_fd);
1208 detach_prog:
1209 if (use_link) {
1210 if (link_fd >= 0)
1211 close(link_fd);
1212 } else {
1213 bpf_prog_detach2(prog_fd, cgroup_fd, test->attach_type);
1214 }
1215 close_prog_fd:
1216 close(prog_fd);
1217 return ret;
1218 }
1219
test_sockopt(void)1220 void test_sockopt(void)
1221 {
1222 int cgroup_fd, i;
1223
1224 cgroup_fd = test__join_cgroup("/sockopt");
1225 if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup"))
1226 return;
1227
1228 for (i = 0; i < ARRAY_SIZE(tests); i++) {
1229 if (!test__start_subtest(tests[i].descr))
1230 continue;
1231
1232 ASSERT_OK(run_test(cgroup_fd, &tests[i], false, false),
1233 tests[i].descr);
1234 ASSERT_OK(run_test(cgroup_fd, &tests[i], false, true),
1235 tests[i].descr);
1236 if (tests[i].io_uring_support)
1237 ASSERT_OK(run_test(cgroup_fd, &tests[i], true, false),
1238 tests[i].descr);
1239 }
1240
1241 close(cgroup_fd);
1242 }
1243