1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include "cgroup_helpers.h"
5 static char bpf_log_buf[4096];
8 enum sockopt_test_error {
18 static struct sockopt_test {
20 const struct bpf_insn insns[64];
21 enum bpf_attach_type attach_type;
22 enum bpf_attach_type expected_attach_type;
26 const char set_optval[64];
31 const char get_optval[64];
33 socklen_t get_optlen_ret;
35 enum sockopt_test_error error;
38 /* ==================== getsockopt ==================== */
41 .descr = "getsockopt: no expected_attach_type",
44 BPF_MOV64_IMM(BPF_REG_0, 1),
48 .attach_type = BPF_CGROUP_GETSOCKOPT,
49 .expected_attach_type = 0,
53 .descr = "getsockopt: wrong expected_attach_type",
56 BPF_MOV64_IMM(BPF_REG_0, 1),
60 .attach_type = BPF_CGROUP_GETSOCKOPT,
61 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
65 .descr = "getsockopt: bypass bpf hook",
68 BPF_MOV64_IMM(BPF_REG_0, 1),
71 .attach_type = BPF_CGROUP_GETSOCKOPT,
72 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
77 .get_optname = IP_TOS,
78 .set_optname = IP_TOS,
80 .set_optval = { 1 << 3 },
83 .get_optval = { 1 << 3 },
87 .descr = "getsockopt: return EPERM from bpf hook",
89 BPF_MOV64_IMM(BPF_REG_0, 0),
92 .attach_type = BPF_CGROUP_GETSOCKOPT,
93 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
96 .get_optname = IP_TOS,
99 .error = EPERM_GETSOCKOPT,
102 .descr = "getsockopt: no optval bounds check, deny loading",
104 /* r6 = ctx->optval */
105 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
106 offsetof(struct bpf_sockopt, optval)),
108 /* ctx->optval[0] = 0x80 */
109 BPF_MOV64_IMM(BPF_REG_0, 0x80),
110 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_0, 0),
113 BPF_MOV64_IMM(BPF_REG_0, 1),
116 .attach_type = BPF_CGROUP_GETSOCKOPT,
117 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
121 .descr = "getsockopt: read ctx->level",
123 /* r6 = ctx->level */
124 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
125 offsetof(struct bpf_sockopt, level)),
127 /* if (ctx->level == 123) { */
128 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
129 /* ctx->retval = 0 */
130 BPF_MOV64_IMM(BPF_REG_0, 0),
131 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
132 offsetof(struct bpf_sockopt, retval)),
134 BPF_MOV64_IMM(BPF_REG_0, 1),
138 BPF_MOV64_IMM(BPF_REG_0, 0),
142 .attach_type = BPF_CGROUP_GETSOCKOPT,
143 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
150 .descr = "getsockopt: deny writing to ctx->level",
153 BPF_MOV64_IMM(BPF_REG_0, 1),
154 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
155 offsetof(struct bpf_sockopt, level)),
158 .attach_type = BPF_CGROUP_GETSOCKOPT,
159 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
164 .descr = "getsockopt: read ctx->optname",
166 /* r6 = ctx->optname */
167 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
168 offsetof(struct bpf_sockopt, optname)),
170 /* if (ctx->optname == 123) { */
171 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
172 /* ctx->retval = 0 */
173 BPF_MOV64_IMM(BPF_REG_0, 0),
174 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
175 offsetof(struct bpf_sockopt, retval)),
177 BPF_MOV64_IMM(BPF_REG_0, 1),
181 BPF_MOV64_IMM(BPF_REG_0, 0),
185 .attach_type = BPF_CGROUP_GETSOCKOPT,
186 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
193 .descr = "getsockopt: read ctx->retval",
195 /* r6 = ctx->retval */
196 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
197 offsetof(struct bpf_sockopt, retval)),
200 BPF_MOV64_IMM(BPF_REG_0, 1),
203 .attach_type = BPF_CGROUP_GETSOCKOPT,
204 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
207 .get_optname = IP_TOS,
211 .descr = "getsockopt: deny writing to ctx->optname",
213 /* ctx->optname = 1 */
214 BPF_MOV64_IMM(BPF_REG_0, 1),
215 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
216 offsetof(struct bpf_sockopt, optname)),
219 .attach_type = BPF_CGROUP_GETSOCKOPT,
220 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
225 .descr = "getsockopt: read ctx->optlen",
227 /* r6 = ctx->optlen */
228 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
229 offsetof(struct bpf_sockopt, optlen)),
231 /* if (ctx->optlen == 64) { */
232 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4),
233 /* ctx->retval = 0 */
234 BPF_MOV64_IMM(BPF_REG_0, 0),
235 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
236 offsetof(struct bpf_sockopt, retval)),
238 BPF_MOV64_IMM(BPF_REG_0, 1),
242 BPF_MOV64_IMM(BPF_REG_0, 0),
246 .attach_type = BPF_CGROUP_GETSOCKOPT,
247 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
252 .descr = "getsockopt: deny bigger ctx->optlen",
254 /* ctx->optlen = 65 */
255 BPF_MOV64_IMM(BPF_REG_0, 65),
256 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
257 offsetof(struct bpf_sockopt, optlen)),
259 /* ctx->retval = 0 */
260 BPF_MOV64_IMM(BPF_REG_0, 0),
261 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
262 offsetof(struct bpf_sockopt, retval)),
265 BPF_MOV64_IMM(BPF_REG_0, 1),
268 .attach_type = BPF_CGROUP_GETSOCKOPT,
269 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
273 .error = EFAULT_GETSOCKOPT,
276 .descr = "getsockopt: deny arbitrary ctx->retval",
278 /* ctx->retval = 123 */
279 BPF_MOV64_IMM(BPF_REG_0, 123),
280 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
281 offsetof(struct bpf_sockopt, retval)),
284 BPF_MOV64_IMM(BPF_REG_0, 1),
287 .attach_type = BPF_CGROUP_GETSOCKOPT,
288 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
292 .error = EFAULT_GETSOCKOPT,
295 .descr = "getsockopt: support smaller ctx->optlen",
297 /* ctx->optlen = 32 */
298 BPF_MOV64_IMM(BPF_REG_0, 32),
299 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
300 offsetof(struct bpf_sockopt, optlen)),
301 /* ctx->retval = 0 */
302 BPF_MOV64_IMM(BPF_REG_0, 0),
303 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
304 offsetof(struct bpf_sockopt, retval)),
306 BPF_MOV64_IMM(BPF_REG_0, 1),
309 .attach_type = BPF_CGROUP_GETSOCKOPT,
310 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
313 .get_optlen_ret = 32,
316 .descr = "getsockopt: deny writing to ctx->optval",
318 /* ctx->optval = 1 */
319 BPF_MOV64_IMM(BPF_REG_0, 1),
320 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
321 offsetof(struct bpf_sockopt, optval)),
324 .attach_type = BPF_CGROUP_GETSOCKOPT,
325 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
330 .descr = "getsockopt: deny writing to ctx->optval_end",
332 /* ctx->optval_end = 1 */
333 BPF_MOV64_IMM(BPF_REG_0, 1),
334 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
335 offsetof(struct bpf_sockopt, optval_end)),
338 .attach_type = BPF_CGROUP_GETSOCKOPT,
339 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
344 .descr = "getsockopt: rewrite value",
346 /* r6 = ctx->optval */
347 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
348 offsetof(struct bpf_sockopt, optval)),
349 /* r2 = ctx->optval */
350 BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
351 /* r6 = ctx->optval + 1 */
352 BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),
354 /* r7 = ctx->optval_end */
355 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,
356 offsetof(struct bpf_sockopt, optval_end)),
358 /* if (ctx->optval + 1 <= ctx->optval_end) { */
359 BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),
360 /* ctx->optval[0] = 0xF0 */
361 BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0),
364 /* ctx->retval = 0 */
365 BPF_MOV64_IMM(BPF_REG_0, 0),
366 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
367 offsetof(struct bpf_sockopt, retval)),
370 BPF_MOV64_IMM(BPF_REG_0, 1),
373 .attach_type = BPF_CGROUP_GETSOCKOPT,
374 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
377 .get_optname = IP_TOS,
379 .get_optval = { 0xF0 },
383 /* ==================== setsockopt ==================== */
386 .descr = "setsockopt: no expected_attach_type",
389 BPF_MOV64_IMM(BPF_REG_0, 1),
393 .attach_type = BPF_CGROUP_SETSOCKOPT,
394 .expected_attach_type = 0,
398 .descr = "setsockopt: wrong expected_attach_type",
401 BPF_MOV64_IMM(BPF_REG_0, 1),
405 .attach_type = BPF_CGROUP_SETSOCKOPT,
406 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
407 .error = DENY_ATTACH,
410 .descr = "setsockopt: bypass bpf hook",
413 BPF_MOV64_IMM(BPF_REG_0, 1),
416 .attach_type = BPF_CGROUP_SETSOCKOPT,
417 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
422 .get_optname = IP_TOS,
423 .set_optname = IP_TOS,
425 .set_optval = { 1 << 3 },
428 .get_optval = { 1 << 3 },
432 .descr = "setsockopt: return EPERM from bpf hook",
435 BPF_MOV64_IMM(BPF_REG_0, 0),
438 .attach_type = BPF_CGROUP_SETSOCKOPT,
439 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
442 .set_optname = IP_TOS,
445 .error = EPERM_SETSOCKOPT,
448 .descr = "setsockopt: no optval bounds check, deny loading",
450 /* r6 = ctx->optval */
451 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
452 offsetof(struct bpf_sockopt, optval)),
454 /* r0 = ctx->optval[0] */
455 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6, 0),
458 BPF_MOV64_IMM(BPF_REG_0, 1),
461 .attach_type = BPF_CGROUP_SETSOCKOPT,
462 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
466 .descr = "setsockopt: read ctx->level",
468 /* r6 = ctx->level */
469 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
470 offsetof(struct bpf_sockopt, level)),
472 /* if (ctx->level == 123) { */
473 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
474 /* ctx->optlen = -1 */
475 BPF_MOV64_IMM(BPF_REG_0, -1),
476 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
477 offsetof(struct bpf_sockopt, optlen)),
479 BPF_MOV64_IMM(BPF_REG_0, 1),
483 BPF_MOV64_IMM(BPF_REG_0, 0),
487 .attach_type = BPF_CGROUP_SETSOCKOPT,
488 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
495 .descr = "setsockopt: allow changing ctx->level",
497 /* ctx->level = SOL_IP */
498 BPF_MOV64_IMM(BPF_REG_0, SOL_IP),
499 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
500 offsetof(struct bpf_sockopt, level)),
502 BPF_MOV64_IMM(BPF_REG_0, 1),
505 .attach_type = BPF_CGROUP_SETSOCKOPT,
506 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
509 .set_level = 234, /* should be rewritten to SOL_IP */
511 .get_optname = IP_TOS,
512 .set_optname = IP_TOS,
514 .set_optval = { 1 << 3 },
516 .get_optval = { 1 << 3 },
520 .descr = "setsockopt: read ctx->optname",
522 /* r6 = ctx->optname */
523 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
524 offsetof(struct bpf_sockopt, optname)),
526 /* if (ctx->optname == 123) { */
527 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
528 /* ctx->optlen = -1 */
529 BPF_MOV64_IMM(BPF_REG_0, -1),
530 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
531 offsetof(struct bpf_sockopt, optlen)),
533 BPF_MOV64_IMM(BPF_REG_0, 1),
537 BPF_MOV64_IMM(BPF_REG_0, 0),
541 .attach_type = BPF_CGROUP_SETSOCKOPT,
542 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
549 .descr = "setsockopt: allow changing ctx->optname",
551 /* ctx->optname = IP_TOS */
552 BPF_MOV64_IMM(BPF_REG_0, IP_TOS),
553 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
554 offsetof(struct bpf_sockopt, optname)),
556 BPF_MOV64_IMM(BPF_REG_0, 1),
559 .attach_type = BPF_CGROUP_SETSOCKOPT,
560 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
565 .get_optname = IP_TOS,
566 .set_optname = 456, /* should be rewritten to IP_TOS */
568 .set_optval = { 1 << 3 },
570 .get_optval = { 1 << 3 },
574 .descr = "setsockopt: read ctx->optlen",
576 /* r6 = ctx->optlen */
577 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
578 offsetof(struct bpf_sockopt, optlen)),
580 /* if (ctx->optlen == 64) { */
581 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4),
582 /* ctx->optlen = -1 */
583 BPF_MOV64_IMM(BPF_REG_0, -1),
584 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
585 offsetof(struct bpf_sockopt, optlen)),
587 BPF_MOV64_IMM(BPF_REG_0, 1),
591 BPF_MOV64_IMM(BPF_REG_0, 0),
595 .attach_type = BPF_CGROUP_SETSOCKOPT,
596 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
601 .descr = "setsockopt: ctx->optlen == -1 is ok",
603 /* ctx->optlen = -1 */
604 BPF_MOV64_IMM(BPF_REG_0, -1),
605 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
606 offsetof(struct bpf_sockopt, optlen)),
608 BPF_MOV64_IMM(BPF_REG_0, 1),
611 .attach_type = BPF_CGROUP_SETSOCKOPT,
612 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
617 .descr = "setsockopt: deny ctx->optlen < 0 (except -1)",
619 /* ctx->optlen = -2 */
620 BPF_MOV64_IMM(BPF_REG_0, -2),
621 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
622 offsetof(struct bpf_sockopt, optlen)),
624 BPF_MOV64_IMM(BPF_REG_0, 1),
627 .attach_type = BPF_CGROUP_SETSOCKOPT,
628 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
632 .error = EFAULT_SETSOCKOPT,
635 .descr = "setsockopt: deny ctx->optlen > input optlen",
637 /* ctx->optlen = 65 */
638 BPF_MOV64_IMM(BPF_REG_0, 65),
639 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
640 offsetof(struct bpf_sockopt, optlen)),
641 BPF_MOV64_IMM(BPF_REG_0, 1),
644 .attach_type = BPF_CGROUP_SETSOCKOPT,
645 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
649 .error = EFAULT_SETSOCKOPT,
652 .descr = "setsockopt: allow changing ctx->optlen within bounds",
654 /* r6 = ctx->optval */
655 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
656 offsetof(struct bpf_sockopt, optval)),
657 /* r2 = ctx->optval */
658 BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
659 /* r6 = ctx->optval + 1 */
660 BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),
662 /* r7 = ctx->optval_end */
663 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,
664 offsetof(struct bpf_sockopt, optval_end)),
666 /* if (ctx->optval + 1 <= ctx->optval_end) { */
667 BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),
668 /* ctx->optval[0] = 1 << 3 */
669 BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 1 << 3),
672 /* ctx->optlen = 1 */
673 BPF_MOV64_IMM(BPF_REG_0, 1),
674 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
675 offsetof(struct bpf_sockopt, optlen)),
678 BPF_MOV64_IMM(BPF_REG_0, 1),
681 .attach_type = BPF_CGROUP_SETSOCKOPT,
682 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
687 .get_optname = IP_TOS,
688 .set_optname = IP_TOS,
690 .set_optval = { 1, 1, 1, 1 },
692 .get_optval = { 1 << 3 },
696 .descr = "setsockopt: deny write ctx->retval",
698 /* ctx->retval = 0 */
699 BPF_MOV64_IMM(BPF_REG_0, 0),
700 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
701 offsetof(struct bpf_sockopt, retval)),
704 BPF_MOV64_IMM(BPF_REG_0, 1),
707 .attach_type = BPF_CGROUP_SETSOCKOPT,
708 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
713 .descr = "setsockopt: deny read ctx->retval",
715 /* r6 = ctx->retval */
716 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
717 offsetof(struct bpf_sockopt, retval)),
720 BPF_MOV64_IMM(BPF_REG_0, 1),
723 .attach_type = BPF_CGROUP_SETSOCKOPT,
724 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
729 .descr = "setsockopt: deny writing to ctx->optval",
731 /* ctx->optval = 1 */
732 BPF_MOV64_IMM(BPF_REG_0, 1),
733 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
734 offsetof(struct bpf_sockopt, optval)),
737 .attach_type = BPF_CGROUP_SETSOCKOPT,
738 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
743 .descr = "setsockopt: deny writing to ctx->optval_end",
745 /* ctx->optval_end = 1 */
746 BPF_MOV64_IMM(BPF_REG_0, 1),
747 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
748 offsetof(struct bpf_sockopt, optval_end)),
751 .attach_type = BPF_CGROUP_SETSOCKOPT,
752 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
757 .descr = "setsockopt: allow IP_TOS <= 128",
759 /* r6 = ctx->optval */
760 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
761 offsetof(struct bpf_sockopt, optval)),
762 /* r7 = ctx->optval + 1 */
763 BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
764 BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
766 /* r8 = ctx->optval_end */
767 BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1,
768 offsetof(struct bpf_sockopt, optval_end)),
770 /* if (ctx->optval + 1 <= ctx->optval_end) { */
771 BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4),
773 /* r9 = ctx->optval[0] */
774 BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0),
776 /* if (ctx->optval[0] < 128) */
777 BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2),
778 BPF_MOV64_IMM(BPF_REG_0, 1),
783 BPF_MOV64_IMM(BPF_REG_0, 0),
788 .attach_type = BPF_CGROUP_SETSOCKOPT,
789 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
794 .get_optname = IP_TOS,
795 .set_optname = IP_TOS,
797 .set_optval = { 0x80 },
799 .get_optval = { 0x80 },
803 .descr = "setsockopt: deny IP_TOS > 128",
805 /* r6 = ctx->optval */
806 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
807 offsetof(struct bpf_sockopt, optval)),
808 /* r7 = ctx->optval + 1 */
809 BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
810 BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
812 /* r8 = ctx->optval_end */
813 BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1,
814 offsetof(struct bpf_sockopt, optval_end)),
816 /* if (ctx->optval + 1 <= ctx->optval_end) { */
817 BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4),
819 /* r9 = ctx->optval[0] */
820 BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0),
822 /* if (ctx->optval[0] < 128) */
823 BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2),
824 BPF_MOV64_IMM(BPF_REG_0, 1),
829 BPF_MOV64_IMM(BPF_REG_0, 0),
834 .attach_type = BPF_CGROUP_SETSOCKOPT,
835 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
840 .get_optname = IP_TOS,
841 .set_optname = IP_TOS,
843 .set_optval = { 0x81 },
845 .get_optval = { 0x00 },
848 .error = EPERM_SETSOCKOPT,
852 static int load_prog(const struct bpf_insn *insns,
853 enum bpf_attach_type expected_attach_type)
855 struct bpf_load_program_attr attr = {
856 .prog_type = BPF_PROG_TYPE_CGROUP_SOCKOPT,
857 .expected_attach_type = expected_attach_type,
865 insns[attr.insns_cnt].code != (BPF_JMP | BPF_EXIT);
870 fd = bpf_load_program_xattr(&attr, bpf_log_buf, sizeof(bpf_log_buf));
871 if (verbose && fd < 0)
872 fprintf(stderr, "%s\n", bpf_log_buf);
877 static int run_test(int cgroup_fd, struct sockopt_test *test)
879 int sock_fd, err, prog_fd;
883 prog_fd = load_prog(test->insns, test->expected_attach_type);
885 if (test->error == DENY_LOAD)
888 log_err("Failed to load BPF program");
892 err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0);
894 if (test->error == DENY_ATTACH)
897 log_err("Failed to attach BPF program");
902 sock_fd = socket(AF_INET, SOCK_STREAM, 0);
904 log_err("Failed to create AF_INET socket");
909 if (test->set_optlen) {
910 err = setsockopt(sock_fd, test->set_level, test->set_optname,
911 test->set_optval, test->set_optlen);
913 if (errno == EPERM && test->error == EPERM_SETSOCKOPT)
915 if (errno == EFAULT && test->error == EFAULT_SETSOCKOPT)
918 log_err("Failed to call setsockopt");
924 if (test->get_optlen) {
925 optval = malloc(test->get_optlen);
926 socklen_t optlen = test->get_optlen;
927 socklen_t expected_get_optlen = test->get_optlen_ret ?:
930 err = getsockopt(sock_fd, test->get_level, test->get_optname,
933 if (errno == EPERM && test->error == EPERM_GETSOCKOPT)
935 if (errno == EFAULT && test->error == EFAULT_GETSOCKOPT)
938 log_err("Failed to call getsockopt");
943 if (optlen != expected_get_optlen) {
945 log_err("getsockopt returned unexpected optlen");
950 if (memcmp(optval, test->get_optval, optlen) != 0) {
952 log_err("getsockopt returned unexpected optval");
958 ret = test->error != OK;
965 bpf_prog_detach2(prog_fd, cgroup_fd, test->attach_type);
971 void test_sockopt(void)
975 cgroup_fd = test__join_cgroup("/sockopt");
976 if (CHECK_FAIL(cgroup_fd < 0))
979 for (i = 0; i < ARRAY_SIZE(tests); i++) {
980 test__start_subtest(tests[i].descr);
981 CHECK_FAIL(run_test(cgroup_fd, &tests[i]));