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
]));