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