1 // SPDX-License-Identifier: GPL-2.0
7 #include <sys/socket.h>
8 #include <netinet/in.h>
10 #include <linux/filter.h>
12 #include <bpf/libbpf.h>
14 #include "bpf_rlimit.h"
16 #include "cgroup_helpers.h"
18 #define CG_PATH "/sockopt"
20 static char bpf_log_buf
[4096];
23 enum sockopt_test_error
{
33 static struct sockopt_test
{
35 const struct bpf_insn insns
[64];
36 enum bpf_attach_type attach_type
;
37 enum bpf_attach_type expected_attach_type
;
41 const char set_optval
[64];
46 const char get_optval
[64];
48 socklen_t get_optlen_ret
;
50 enum sockopt_test_error error
;
53 /* ==================== getsockopt ==================== */
56 .descr
= "getsockopt: no expected_attach_type",
59 BPF_MOV64_IMM(BPF_REG_0
, 1),
63 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
64 .expected_attach_type
= 0,
68 .descr
= "getsockopt: wrong expected_attach_type",
71 BPF_MOV64_IMM(BPF_REG_0
, 1),
75 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
76 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
80 .descr
= "getsockopt: bypass bpf hook",
83 BPF_MOV64_IMM(BPF_REG_0
, 1),
86 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
87 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
92 .get_optname
= IP_TOS
,
93 .set_optname
= IP_TOS
,
95 .set_optval
= { 1 << 3 },
98 .get_optval
= { 1 << 3 },
102 .descr
= "getsockopt: return EPERM from bpf hook",
104 BPF_MOV64_IMM(BPF_REG_0
, 0),
107 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
108 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
111 .get_optname
= IP_TOS
,
114 .error
= EPERM_GETSOCKOPT
,
117 .descr
= "getsockopt: no optval bounds check, deny loading",
119 /* r6 = ctx->optval */
120 BPF_LDX_MEM(BPF_DW
, BPF_REG_6
, BPF_REG_1
,
121 offsetof(struct bpf_sockopt
, optval
)),
123 /* ctx->optval[0] = 0x80 */
124 BPF_MOV64_IMM(BPF_REG_0
, 0x80),
125 BPF_STX_MEM(BPF_W
, BPF_REG_6
, BPF_REG_0
, 0),
128 BPF_MOV64_IMM(BPF_REG_0
, 1),
131 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
132 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
136 .descr
= "getsockopt: read ctx->level",
138 /* r6 = ctx->level */
139 BPF_LDX_MEM(BPF_W
, BPF_REG_6
, BPF_REG_1
,
140 offsetof(struct bpf_sockopt
, level
)),
142 /* if (ctx->level == 123) { */
143 BPF_JMP_IMM(BPF_JNE
, BPF_REG_6
, 123, 4),
144 /* ctx->retval = 0 */
145 BPF_MOV64_IMM(BPF_REG_0
, 0),
146 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
147 offsetof(struct bpf_sockopt
, retval
)),
149 BPF_MOV64_IMM(BPF_REG_0
, 1),
153 BPF_MOV64_IMM(BPF_REG_0
, 0),
157 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
158 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
165 .descr
= "getsockopt: deny writing to ctx->level",
168 BPF_MOV64_IMM(BPF_REG_0
, 1),
169 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
170 offsetof(struct bpf_sockopt
, level
)),
173 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
174 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
179 .descr
= "getsockopt: read ctx->optname",
181 /* r6 = ctx->optname */
182 BPF_LDX_MEM(BPF_W
, BPF_REG_6
, BPF_REG_1
,
183 offsetof(struct bpf_sockopt
, optname
)),
185 /* if (ctx->optname == 123) { */
186 BPF_JMP_IMM(BPF_JNE
, BPF_REG_6
, 123, 4),
187 /* ctx->retval = 0 */
188 BPF_MOV64_IMM(BPF_REG_0
, 0),
189 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
190 offsetof(struct bpf_sockopt
, retval
)),
192 BPF_MOV64_IMM(BPF_REG_0
, 1),
196 BPF_MOV64_IMM(BPF_REG_0
, 0),
200 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
201 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
208 .descr
= "getsockopt: read ctx->retval",
210 /* r6 = ctx->retval */
211 BPF_LDX_MEM(BPF_W
, BPF_REG_6
, BPF_REG_1
,
212 offsetof(struct bpf_sockopt
, retval
)),
215 BPF_MOV64_IMM(BPF_REG_0
, 1),
218 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
219 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
222 .get_optname
= IP_TOS
,
226 .descr
= "getsockopt: deny writing to ctx->optname",
228 /* ctx->optname = 1 */
229 BPF_MOV64_IMM(BPF_REG_0
, 1),
230 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
231 offsetof(struct bpf_sockopt
, optname
)),
234 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
235 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
240 .descr
= "getsockopt: read ctx->optlen",
242 /* r6 = ctx->optlen */
243 BPF_LDX_MEM(BPF_W
, BPF_REG_6
, BPF_REG_1
,
244 offsetof(struct bpf_sockopt
, optlen
)),
246 /* if (ctx->optlen == 64) { */
247 BPF_JMP_IMM(BPF_JNE
, BPF_REG_6
, 64, 4),
248 /* ctx->retval = 0 */
249 BPF_MOV64_IMM(BPF_REG_0
, 0),
250 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
251 offsetof(struct bpf_sockopt
, retval
)),
253 BPF_MOV64_IMM(BPF_REG_0
, 1),
257 BPF_MOV64_IMM(BPF_REG_0
, 0),
261 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
262 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
267 .descr
= "getsockopt: deny bigger ctx->optlen",
269 /* ctx->optlen = 65 */
270 BPF_MOV64_IMM(BPF_REG_0
, 65),
271 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
272 offsetof(struct bpf_sockopt
, optlen
)),
274 /* ctx->retval = 0 */
275 BPF_MOV64_IMM(BPF_REG_0
, 0),
276 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
277 offsetof(struct bpf_sockopt
, retval
)),
280 BPF_MOV64_IMM(BPF_REG_0
, 1),
283 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
284 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
288 .error
= EFAULT_GETSOCKOPT
,
291 .descr
= "getsockopt: deny arbitrary ctx->retval",
293 /* ctx->retval = 123 */
294 BPF_MOV64_IMM(BPF_REG_0
, 123),
295 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
296 offsetof(struct bpf_sockopt
, retval
)),
299 BPF_MOV64_IMM(BPF_REG_0
, 1),
302 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
303 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
307 .error
= EFAULT_GETSOCKOPT
,
310 .descr
= "getsockopt: support smaller ctx->optlen",
312 /* ctx->optlen = 32 */
313 BPF_MOV64_IMM(BPF_REG_0
, 32),
314 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
315 offsetof(struct bpf_sockopt
, optlen
)),
316 /* ctx->retval = 0 */
317 BPF_MOV64_IMM(BPF_REG_0
, 0),
318 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
319 offsetof(struct bpf_sockopt
, retval
)),
321 BPF_MOV64_IMM(BPF_REG_0
, 1),
324 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
325 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
328 .get_optlen_ret
= 32,
331 .descr
= "getsockopt: deny writing to ctx->optval",
333 /* ctx->optval = 1 */
334 BPF_MOV64_IMM(BPF_REG_0
, 1),
335 BPF_STX_MEM(BPF_DW
, BPF_REG_1
, BPF_REG_0
,
336 offsetof(struct bpf_sockopt
, optval
)),
339 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
340 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
345 .descr
= "getsockopt: deny writing to ctx->optval_end",
347 /* ctx->optval_end = 1 */
348 BPF_MOV64_IMM(BPF_REG_0
, 1),
349 BPF_STX_MEM(BPF_DW
, BPF_REG_1
, BPF_REG_0
,
350 offsetof(struct bpf_sockopt
, optval_end
)),
353 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
354 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
359 .descr
= "getsockopt: rewrite value",
361 /* r6 = ctx->optval */
362 BPF_LDX_MEM(BPF_DW
, BPF_REG_6
, BPF_REG_1
,
363 offsetof(struct bpf_sockopt
, optval
)),
364 /* r2 = ctx->optval */
365 BPF_MOV64_REG(BPF_REG_2
, BPF_REG_6
),
366 /* r6 = ctx->optval + 1 */
367 BPF_ALU64_IMM(BPF_ADD
, BPF_REG_6
, 1),
369 /* r7 = ctx->optval_end */
370 BPF_LDX_MEM(BPF_DW
, BPF_REG_7
, BPF_REG_1
,
371 offsetof(struct bpf_sockopt
, optval_end
)),
373 /* if (ctx->optval + 1 <= ctx->optval_end) { */
374 BPF_JMP_REG(BPF_JGT
, BPF_REG_6
, BPF_REG_7
, 1),
375 /* ctx->optval[0] = 0xF0 */
376 BPF_ST_MEM(BPF_B
, BPF_REG_2
, 0, 0xF0),
379 /* ctx->retval = 0 */
380 BPF_MOV64_IMM(BPF_REG_0
, 0),
381 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
382 offsetof(struct bpf_sockopt
, retval
)),
385 BPF_MOV64_IMM(BPF_REG_0
, 1),
388 .attach_type
= BPF_CGROUP_GETSOCKOPT
,
389 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
392 .get_optname
= IP_TOS
,
394 .get_optval
= { 0xF0 },
398 /* ==================== setsockopt ==================== */
401 .descr
= "setsockopt: no expected_attach_type",
404 BPF_MOV64_IMM(BPF_REG_0
, 1),
408 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
409 .expected_attach_type
= 0,
413 .descr
= "setsockopt: wrong expected_attach_type",
416 BPF_MOV64_IMM(BPF_REG_0
, 1),
420 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
421 .expected_attach_type
= BPF_CGROUP_GETSOCKOPT
,
422 .error
= DENY_ATTACH
,
425 .descr
= "setsockopt: bypass bpf hook",
428 BPF_MOV64_IMM(BPF_REG_0
, 1),
431 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
432 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
437 .get_optname
= IP_TOS
,
438 .set_optname
= IP_TOS
,
440 .set_optval
= { 1 << 3 },
443 .get_optval
= { 1 << 3 },
447 .descr
= "setsockopt: return EPERM from bpf hook",
450 BPF_MOV64_IMM(BPF_REG_0
, 0),
453 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
454 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
457 .set_optname
= IP_TOS
,
460 .error
= EPERM_SETSOCKOPT
,
463 .descr
= "setsockopt: no optval bounds check, deny loading",
465 /* r6 = ctx->optval */
466 BPF_LDX_MEM(BPF_DW
, BPF_REG_6
, BPF_REG_1
,
467 offsetof(struct bpf_sockopt
, optval
)),
469 /* r0 = ctx->optval[0] */
470 BPF_LDX_MEM(BPF_W
, BPF_REG_0
, BPF_REG_6
, 0),
473 BPF_MOV64_IMM(BPF_REG_0
, 1),
476 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
477 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
481 .descr
= "setsockopt: read ctx->level",
483 /* r6 = ctx->level */
484 BPF_LDX_MEM(BPF_W
, BPF_REG_6
, BPF_REG_1
,
485 offsetof(struct bpf_sockopt
, level
)),
487 /* if (ctx->level == 123) { */
488 BPF_JMP_IMM(BPF_JNE
, BPF_REG_6
, 123, 4),
489 /* ctx->optlen = -1 */
490 BPF_MOV64_IMM(BPF_REG_0
, -1),
491 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
492 offsetof(struct bpf_sockopt
, optlen
)),
494 BPF_MOV64_IMM(BPF_REG_0
, 1),
498 BPF_MOV64_IMM(BPF_REG_0
, 0),
502 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
503 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
510 .descr
= "setsockopt: allow changing ctx->level",
512 /* ctx->level = SOL_IP */
513 BPF_MOV64_IMM(BPF_REG_0
, SOL_IP
),
514 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
515 offsetof(struct bpf_sockopt
, level
)),
517 BPF_MOV64_IMM(BPF_REG_0
, 1),
520 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
521 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
524 .set_level
= 234, /* should be rewritten to SOL_IP */
526 .get_optname
= IP_TOS
,
527 .set_optname
= IP_TOS
,
529 .set_optval
= { 1 << 3 },
531 .get_optval
= { 1 << 3 },
535 .descr
= "setsockopt: read ctx->optname",
537 /* r6 = ctx->optname */
538 BPF_LDX_MEM(BPF_W
, BPF_REG_6
, BPF_REG_1
,
539 offsetof(struct bpf_sockopt
, optname
)),
541 /* if (ctx->optname == 123) { */
542 BPF_JMP_IMM(BPF_JNE
, BPF_REG_6
, 123, 4),
543 /* ctx->optlen = -1 */
544 BPF_MOV64_IMM(BPF_REG_0
, -1),
545 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
546 offsetof(struct bpf_sockopt
, optlen
)),
548 BPF_MOV64_IMM(BPF_REG_0
, 1),
552 BPF_MOV64_IMM(BPF_REG_0
, 0),
556 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
557 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
564 .descr
= "setsockopt: allow changing ctx->optname",
566 /* ctx->optname = IP_TOS */
567 BPF_MOV64_IMM(BPF_REG_0
, IP_TOS
),
568 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
569 offsetof(struct bpf_sockopt
, optname
)),
571 BPF_MOV64_IMM(BPF_REG_0
, 1),
574 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
575 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
580 .get_optname
= IP_TOS
,
581 .set_optname
= 456, /* should be rewritten to IP_TOS */
583 .set_optval
= { 1 << 3 },
585 .get_optval
= { 1 << 3 },
589 .descr
= "setsockopt: read ctx->optlen",
591 /* r6 = ctx->optlen */
592 BPF_LDX_MEM(BPF_W
, BPF_REG_6
, BPF_REG_1
,
593 offsetof(struct bpf_sockopt
, optlen
)),
595 /* if (ctx->optlen == 64) { */
596 BPF_JMP_IMM(BPF_JNE
, BPF_REG_6
, 64, 4),
597 /* ctx->optlen = -1 */
598 BPF_MOV64_IMM(BPF_REG_0
, -1),
599 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
600 offsetof(struct bpf_sockopt
, optlen
)),
602 BPF_MOV64_IMM(BPF_REG_0
, 1),
606 BPF_MOV64_IMM(BPF_REG_0
, 0),
610 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
611 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
616 .descr
= "setsockopt: ctx->optlen == -1 is ok",
618 /* ctx->optlen = -1 */
619 BPF_MOV64_IMM(BPF_REG_0
, -1),
620 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
621 offsetof(struct bpf_sockopt
, optlen
)),
623 BPF_MOV64_IMM(BPF_REG_0
, 1),
626 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
627 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
632 .descr
= "setsockopt: deny ctx->optlen < 0 (except -1)",
634 /* ctx->optlen = -2 */
635 BPF_MOV64_IMM(BPF_REG_0
, -2),
636 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
637 offsetof(struct bpf_sockopt
, optlen
)),
639 BPF_MOV64_IMM(BPF_REG_0
, 1),
642 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
643 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
647 .error
= EFAULT_SETSOCKOPT
,
650 .descr
= "setsockopt: deny ctx->optlen > input optlen",
652 /* ctx->optlen = 65 */
653 BPF_MOV64_IMM(BPF_REG_0
, 65),
654 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
655 offsetof(struct bpf_sockopt
, optlen
)),
656 BPF_MOV64_IMM(BPF_REG_0
, 1),
659 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
660 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
664 .error
= EFAULT_SETSOCKOPT
,
667 .descr
= "setsockopt: allow changing ctx->optlen within bounds",
669 /* r6 = ctx->optval */
670 BPF_LDX_MEM(BPF_DW
, BPF_REG_6
, BPF_REG_1
,
671 offsetof(struct bpf_sockopt
, optval
)),
672 /* r2 = ctx->optval */
673 BPF_MOV64_REG(BPF_REG_2
, BPF_REG_6
),
674 /* r6 = ctx->optval + 1 */
675 BPF_ALU64_IMM(BPF_ADD
, BPF_REG_6
, 1),
677 /* r7 = ctx->optval_end */
678 BPF_LDX_MEM(BPF_DW
, BPF_REG_7
, BPF_REG_1
,
679 offsetof(struct bpf_sockopt
, optval_end
)),
681 /* if (ctx->optval + 1 <= ctx->optval_end) { */
682 BPF_JMP_REG(BPF_JGT
, BPF_REG_6
, BPF_REG_7
, 1),
683 /* ctx->optval[0] = 1 << 3 */
684 BPF_ST_MEM(BPF_B
, BPF_REG_2
, 0, 1 << 3),
687 /* ctx->optlen = 1 */
688 BPF_MOV64_IMM(BPF_REG_0
, 1),
689 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
690 offsetof(struct bpf_sockopt
, optlen
)),
693 BPF_MOV64_IMM(BPF_REG_0
, 1),
696 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
697 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
702 .get_optname
= IP_TOS
,
703 .set_optname
= IP_TOS
,
705 .set_optval
= { 1, 1, 1, 1 },
707 .get_optval
= { 1 << 3 },
711 .descr
= "setsockopt: deny write ctx->retval",
713 /* ctx->retval = 0 */
714 BPF_MOV64_IMM(BPF_REG_0
, 0),
715 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_0
,
716 offsetof(struct bpf_sockopt
, retval
)),
719 BPF_MOV64_IMM(BPF_REG_0
, 1),
722 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
723 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
728 .descr
= "setsockopt: deny read ctx->retval",
730 /* r6 = ctx->retval */
731 BPF_LDX_MEM(BPF_W
, BPF_REG_6
, BPF_REG_1
,
732 offsetof(struct bpf_sockopt
, retval
)),
735 BPF_MOV64_IMM(BPF_REG_0
, 1),
738 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
739 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
744 .descr
= "setsockopt: deny writing to ctx->optval",
746 /* ctx->optval = 1 */
747 BPF_MOV64_IMM(BPF_REG_0
, 1),
748 BPF_STX_MEM(BPF_DW
, BPF_REG_1
, BPF_REG_0
,
749 offsetof(struct bpf_sockopt
, optval
)),
752 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
753 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
758 .descr
= "setsockopt: deny writing to ctx->optval_end",
760 /* ctx->optval_end = 1 */
761 BPF_MOV64_IMM(BPF_REG_0
, 1),
762 BPF_STX_MEM(BPF_DW
, BPF_REG_1
, BPF_REG_0
,
763 offsetof(struct bpf_sockopt
, optval_end
)),
766 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
767 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
772 .descr
= "setsockopt: allow IP_TOS <= 128",
774 /* r6 = ctx->optval */
775 BPF_LDX_MEM(BPF_DW
, BPF_REG_6
, BPF_REG_1
,
776 offsetof(struct bpf_sockopt
, optval
)),
777 /* r7 = ctx->optval + 1 */
778 BPF_MOV64_REG(BPF_REG_7
, BPF_REG_6
),
779 BPF_ALU64_IMM(BPF_ADD
, BPF_REG_7
, 1),
781 /* r8 = ctx->optval_end */
782 BPF_LDX_MEM(BPF_DW
, BPF_REG_8
, BPF_REG_1
,
783 offsetof(struct bpf_sockopt
, optval_end
)),
785 /* if (ctx->optval + 1 <= ctx->optval_end) { */
786 BPF_JMP_REG(BPF_JGT
, BPF_REG_7
, BPF_REG_8
, 4),
788 /* r9 = ctx->optval[0] */
789 BPF_LDX_MEM(BPF_B
, BPF_REG_9
, BPF_REG_6
, 0),
791 /* if (ctx->optval[0] < 128) */
792 BPF_JMP_IMM(BPF_JGT
, BPF_REG_9
, 128, 2),
793 BPF_MOV64_IMM(BPF_REG_0
, 1),
798 BPF_MOV64_IMM(BPF_REG_0
, 0),
803 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
804 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
809 .get_optname
= IP_TOS
,
810 .set_optname
= IP_TOS
,
812 .set_optval
= { 0x80 },
814 .get_optval
= { 0x80 },
818 .descr
= "setsockopt: deny IP_TOS > 128",
820 /* r6 = ctx->optval */
821 BPF_LDX_MEM(BPF_DW
, BPF_REG_6
, BPF_REG_1
,
822 offsetof(struct bpf_sockopt
, optval
)),
823 /* r7 = ctx->optval + 1 */
824 BPF_MOV64_REG(BPF_REG_7
, BPF_REG_6
),
825 BPF_ALU64_IMM(BPF_ADD
, BPF_REG_7
, 1),
827 /* r8 = ctx->optval_end */
828 BPF_LDX_MEM(BPF_DW
, BPF_REG_8
, BPF_REG_1
,
829 offsetof(struct bpf_sockopt
, optval_end
)),
831 /* if (ctx->optval + 1 <= ctx->optval_end) { */
832 BPF_JMP_REG(BPF_JGT
, BPF_REG_7
, BPF_REG_8
, 4),
834 /* r9 = ctx->optval[0] */
835 BPF_LDX_MEM(BPF_B
, BPF_REG_9
, BPF_REG_6
, 0),
837 /* if (ctx->optval[0] < 128) */
838 BPF_JMP_IMM(BPF_JGT
, BPF_REG_9
, 128, 2),
839 BPF_MOV64_IMM(BPF_REG_0
, 1),
844 BPF_MOV64_IMM(BPF_REG_0
, 0),
849 .attach_type
= BPF_CGROUP_SETSOCKOPT
,
850 .expected_attach_type
= BPF_CGROUP_SETSOCKOPT
,
855 .get_optname
= IP_TOS
,
856 .set_optname
= IP_TOS
,
858 .set_optval
= { 0x81 },
860 .get_optval
= { 0x00 },
863 .error
= EPERM_SETSOCKOPT
,
867 static int load_prog(const struct bpf_insn
*insns
,
868 enum bpf_attach_type expected_attach_type
)
870 struct bpf_load_program_attr attr
= {
871 .prog_type
= BPF_PROG_TYPE_CGROUP_SOCKOPT
,
872 .expected_attach_type
= expected_attach_type
,
880 insns
[attr
.insns_cnt
].code
!= (BPF_JMP
| BPF_EXIT
);
885 fd
= bpf_load_program_xattr(&attr
, bpf_log_buf
, sizeof(bpf_log_buf
));
886 if (verbose
&& fd
< 0)
887 fprintf(stderr
, "%s\n", bpf_log_buf
);
892 static int run_test(int cgroup_fd
, struct sockopt_test
*test
)
894 int sock_fd
, err
, prog_fd
;
898 prog_fd
= load_prog(test
->insns
, test
->expected_attach_type
);
900 if (test
->error
== DENY_LOAD
)
903 log_err("Failed to load BPF program");
907 err
= bpf_prog_attach(prog_fd
, cgroup_fd
, test
->attach_type
, 0);
909 if (test
->error
== DENY_ATTACH
)
912 log_err("Failed to attach BPF program");
917 sock_fd
= socket(AF_INET
, SOCK_STREAM
, 0);
919 log_err("Failed to create AF_INET socket");
924 if (test
->set_optlen
) {
925 err
= setsockopt(sock_fd
, test
->set_level
, test
->set_optname
,
926 test
->set_optval
, test
->set_optlen
);
928 if (errno
== EPERM
&& test
->error
== EPERM_SETSOCKOPT
)
930 if (errno
== EFAULT
&& test
->error
== EFAULT_SETSOCKOPT
)
933 log_err("Failed to call setsockopt");
939 if (test
->get_optlen
) {
940 optval
= malloc(test
->get_optlen
);
941 socklen_t optlen
= test
->get_optlen
;
942 socklen_t expected_get_optlen
= test
->get_optlen_ret
?:
945 err
= getsockopt(sock_fd
, test
->get_level
, test
->get_optname
,
948 if (errno
== EPERM
&& test
->error
== EPERM_GETSOCKOPT
)
950 if (errno
== EFAULT
&& test
->error
== EFAULT_GETSOCKOPT
)
953 log_err("Failed to call getsockopt");
958 if (optlen
!= expected_get_optlen
) {
960 log_err("getsockopt returned unexpected optlen");
965 if (memcmp(optval
, test
->get_optval
, optlen
) != 0) {
967 log_err("getsockopt returned unexpected optval");
973 ret
= test
->error
!= OK
;
980 bpf_prog_detach2(prog_fd
, cgroup_fd
, test
->attach_type
);
986 int main(int args
, char **argv
)
988 int err
= EXIT_FAILURE
, error_cnt
= 0;
991 if (setup_cgroup_environment())
994 cgroup_fd
= create_and_get_cgroup(CG_PATH
);
996 goto cleanup_cgroup_env
;
998 if (join_cgroup(CG_PATH
))
1001 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++) {
1002 int err
= run_test(cgroup_fd
, &tests
[i
]);
1007 printf("#%d %s: %s\n", i
, err
? "FAIL" : "PASS",
1011 printf("Summary: %ld PASSED, %d FAILED\n",
1012 ARRAY_SIZE(tests
) - error_cnt
, error_cnt
);
1013 err
= error_cnt
? EXIT_FAILURE
: EXIT_SUCCESS
;
1018 cleanup_cgroup_environment();