0001
0002 #include <test_progs.h>
0003 #include "cgroup_helpers.h"
0004
0005 static char bpf_log_buf[4096];
0006 static bool verbose;
0007
0008 enum sockopt_test_error {
0009 OK = 0,
0010 DENY_LOAD,
0011 DENY_ATTACH,
0012 EPERM_GETSOCKOPT,
0013 EFAULT_GETSOCKOPT,
0014 EPERM_SETSOCKOPT,
0015 EFAULT_SETSOCKOPT,
0016 };
0017
0018 static struct sockopt_test {
0019 const char *descr;
0020 const struct bpf_insn insns[64];
0021 enum bpf_attach_type attach_type;
0022 enum bpf_attach_type expected_attach_type;
0023
0024 int set_optname;
0025 int set_level;
0026 const char set_optval[64];
0027 socklen_t set_optlen;
0028
0029 int get_optname;
0030 int get_level;
0031 const char get_optval[64];
0032 socklen_t get_optlen;
0033 socklen_t get_optlen_ret;
0034
0035 enum sockopt_test_error error;
0036 } tests[] = {
0037
0038
0039
0040 {
0041 .descr = "getsockopt: no expected_attach_type",
0042 .insns = {
0043
0044 BPF_MOV64_IMM(BPF_REG_0, 1),
0045 BPF_EXIT_INSN(),
0046
0047 },
0048 .attach_type = BPF_CGROUP_GETSOCKOPT,
0049 .expected_attach_type = 0,
0050 .error = DENY_LOAD,
0051 },
0052 {
0053 .descr = "getsockopt: wrong expected_attach_type",
0054 .insns = {
0055
0056 BPF_MOV64_IMM(BPF_REG_0, 1),
0057 BPF_EXIT_INSN(),
0058
0059 },
0060 .attach_type = BPF_CGROUP_GETSOCKOPT,
0061 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0062 .error = DENY_ATTACH,
0063 },
0064 {
0065 .descr = "getsockopt: bypass bpf hook",
0066 .insns = {
0067
0068 BPF_MOV64_IMM(BPF_REG_0, 1),
0069 BPF_EXIT_INSN(),
0070 },
0071 .attach_type = BPF_CGROUP_GETSOCKOPT,
0072 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0073
0074 .get_level = SOL_IP,
0075 .set_level = SOL_IP,
0076
0077 .get_optname = IP_TOS,
0078 .set_optname = IP_TOS,
0079
0080 .set_optval = { 1 << 3 },
0081 .set_optlen = 1,
0082
0083 .get_optval = { 1 << 3 },
0084 .get_optlen = 1,
0085 },
0086 {
0087 .descr = "getsockopt: return EPERM from bpf hook",
0088 .insns = {
0089 BPF_MOV64_IMM(BPF_REG_0, 0),
0090 BPF_EXIT_INSN(),
0091 },
0092 .attach_type = BPF_CGROUP_GETSOCKOPT,
0093 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0094
0095 .get_level = SOL_IP,
0096 .get_optname = IP_TOS,
0097
0098 .get_optlen = 1,
0099 .error = EPERM_GETSOCKOPT,
0100 },
0101 {
0102 .descr = "getsockopt: no optval bounds check, deny loading",
0103 .insns = {
0104
0105 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
0106 offsetof(struct bpf_sockopt, optval)),
0107
0108
0109 BPF_MOV64_IMM(BPF_REG_0, 0x80),
0110 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_0, 0),
0111
0112
0113 BPF_MOV64_IMM(BPF_REG_0, 1),
0114 BPF_EXIT_INSN(),
0115 },
0116 .attach_type = BPF_CGROUP_GETSOCKOPT,
0117 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0118 .error = DENY_LOAD,
0119 },
0120 {
0121 .descr = "getsockopt: read ctx->level",
0122 .insns = {
0123
0124 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
0125 offsetof(struct bpf_sockopt, level)),
0126
0127
0128 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
0129
0130 BPF_MOV64_IMM(BPF_REG_0, 0),
0131 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0132 offsetof(struct bpf_sockopt, retval)),
0133
0134 BPF_MOV64_IMM(BPF_REG_0, 1),
0135 BPF_JMP_A(1),
0136
0137
0138 BPF_MOV64_IMM(BPF_REG_0, 0),
0139
0140 BPF_EXIT_INSN(),
0141 },
0142 .attach_type = BPF_CGROUP_GETSOCKOPT,
0143 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0144
0145 .get_level = 123,
0146
0147 .get_optlen = 1,
0148 },
0149 {
0150 .descr = "getsockopt: deny writing to ctx->level",
0151 .insns = {
0152
0153 BPF_MOV64_IMM(BPF_REG_0, 1),
0154 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0155 offsetof(struct bpf_sockopt, level)),
0156 BPF_EXIT_INSN(),
0157 },
0158 .attach_type = BPF_CGROUP_GETSOCKOPT,
0159 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0160
0161 .error = DENY_LOAD,
0162 },
0163 {
0164 .descr = "getsockopt: read ctx->optname",
0165 .insns = {
0166
0167 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
0168 offsetof(struct bpf_sockopt, optname)),
0169
0170
0171 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
0172
0173 BPF_MOV64_IMM(BPF_REG_0, 0),
0174 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0175 offsetof(struct bpf_sockopt, retval)),
0176
0177 BPF_MOV64_IMM(BPF_REG_0, 1),
0178 BPF_JMP_A(1),
0179
0180
0181 BPF_MOV64_IMM(BPF_REG_0, 0),
0182
0183 BPF_EXIT_INSN(),
0184 },
0185 .attach_type = BPF_CGROUP_GETSOCKOPT,
0186 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0187
0188 .get_optname = 123,
0189
0190 .get_optlen = 1,
0191 },
0192 {
0193 .descr = "getsockopt: read ctx->retval",
0194 .insns = {
0195
0196 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
0197 offsetof(struct bpf_sockopt, retval)),
0198
0199
0200 BPF_MOV64_IMM(BPF_REG_0, 1),
0201 BPF_EXIT_INSN(),
0202 },
0203 .attach_type = BPF_CGROUP_GETSOCKOPT,
0204 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0205
0206 .get_level = SOL_IP,
0207 .get_optname = IP_TOS,
0208 .get_optlen = 1,
0209 },
0210 {
0211 .descr = "getsockopt: deny writing to ctx->optname",
0212 .insns = {
0213
0214 BPF_MOV64_IMM(BPF_REG_0, 1),
0215 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0216 offsetof(struct bpf_sockopt, optname)),
0217 BPF_EXIT_INSN(),
0218 },
0219 .attach_type = BPF_CGROUP_GETSOCKOPT,
0220 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0221
0222 .error = DENY_LOAD,
0223 },
0224 {
0225 .descr = "getsockopt: read ctx->optlen",
0226 .insns = {
0227
0228 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
0229 offsetof(struct bpf_sockopt, optlen)),
0230
0231
0232 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4),
0233
0234 BPF_MOV64_IMM(BPF_REG_0, 0),
0235 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0236 offsetof(struct bpf_sockopt, retval)),
0237
0238 BPF_MOV64_IMM(BPF_REG_0, 1),
0239 BPF_JMP_A(1),
0240
0241
0242 BPF_MOV64_IMM(BPF_REG_0, 0),
0243
0244 BPF_EXIT_INSN(),
0245 },
0246 .attach_type = BPF_CGROUP_GETSOCKOPT,
0247 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0248
0249 .get_optlen = 64,
0250 },
0251 {
0252 .descr = "getsockopt: deny bigger ctx->optlen",
0253 .insns = {
0254
0255 BPF_MOV64_IMM(BPF_REG_0, 65),
0256 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0257 offsetof(struct bpf_sockopt, optlen)),
0258
0259
0260 BPF_MOV64_IMM(BPF_REG_0, 0),
0261 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0262 offsetof(struct bpf_sockopt, retval)),
0263
0264
0265 BPF_MOV64_IMM(BPF_REG_0, 1),
0266 BPF_EXIT_INSN(),
0267 },
0268 .attach_type = BPF_CGROUP_GETSOCKOPT,
0269 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0270
0271 .get_optlen = 64,
0272
0273 .error = EFAULT_GETSOCKOPT,
0274 },
0275 {
0276 .descr = "getsockopt: deny arbitrary ctx->retval",
0277 .insns = {
0278
0279 BPF_MOV64_IMM(BPF_REG_0, 123),
0280 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0281 offsetof(struct bpf_sockopt, retval)),
0282
0283
0284 BPF_MOV64_IMM(BPF_REG_0, 1),
0285 BPF_EXIT_INSN(),
0286 },
0287 .attach_type = BPF_CGROUP_GETSOCKOPT,
0288 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0289
0290 .get_optlen = 64,
0291
0292 .error = EFAULT_GETSOCKOPT,
0293 },
0294 {
0295 .descr = "getsockopt: support smaller ctx->optlen",
0296 .insns = {
0297
0298 BPF_MOV64_IMM(BPF_REG_0, 32),
0299 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0300 offsetof(struct bpf_sockopt, optlen)),
0301
0302 BPF_MOV64_IMM(BPF_REG_0, 0),
0303 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0304 offsetof(struct bpf_sockopt, retval)),
0305
0306 BPF_MOV64_IMM(BPF_REG_0, 1),
0307 BPF_EXIT_INSN(),
0308 },
0309 .attach_type = BPF_CGROUP_GETSOCKOPT,
0310 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0311
0312 .get_optlen = 64,
0313 .get_optlen_ret = 32,
0314 },
0315 {
0316 .descr = "getsockopt: deny writing to ctx->optval",
0317 .insns = {
0318
0319 BPF_MOV64_IMM(BPF_REG_0, 1),
0320 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
0321 offsetof(struct bpf_sockopt, optval)),
0322 BPF_EXIT_INSN(),
0323 },
0324 .attach_type = BPF_CGROUP_GETSOCKOPT,
0325 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0326
0327 .error = DENY_LOAD,
0328 },
0329 {
0330 .descr = "getsockopt: deny writing to ctx->optval_end",
0331 .insns = {
0332
0333 BPF_MOV64_IMM(BPF_REG_0, 1),
0334 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
0335 offsetof(struct bpf_sockopt, optval_end)),
0336 BPF_EXIT_INSN(),
0337 },
0338 .attach_type = BPF_CGROUP_GETSOCKOPT,
0339 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0340
0341 .error = DENY_LOAD,
0342 },
0343 {
0344 .descr = "getsockopt: rewrite value",
0345 .insns = {
0346
0347 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
0348 offsetof(struct bpf_sockopt, optval)),
0349
0350 BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
0351
0352 BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),
0353
0354
0355 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,
0356 offsetof(struct bpf_sockopt, optval_end)),
0357
0358
0359 BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),
0360
0361 BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0),
0362
0363
0364
0365 BPF_MOV64_IMM(BPF_REG_0, 0),
0366 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0367 offsetof(struct bpf_sockopt, retval)),
0368
0369
0370 BPF_MOV64_IMM(BPF_REG_0, 1),
0371 BPF_EXIT_INSN(),
0372 },
0373 .attach_type = BPF_CGROUP_GETSOCKOPT,
0374 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0375
0376 .get_level = SOL_IP,
0377 .get_optname = IP_TOS,
0378
0379 .get_optval = { 0xF0 },
0380 .get_optlen = 1,
0381 },
0382
0383
0384
0385 {
0386 .descr = "setsockopt: no expected_attach_type",
0387 .insns = {
0388
0389 BPF_MOV64_IMM(BPF_REG_0, 1),
0390 BPF_EXIT_INSN(),
0391
0392 },
0393 .attach_type = BPF_CGROUP_SETSOCKOPT,
0394 .expected_attach_type = 0,
0395 .error = DENY_LOAD,
0396 },
0397 {
0398 .descr = "setsockopt: wrong expected_attach_type",
0399 .insns = {
0400
0401 BPF_MOV64_IMM(BPF_REG_0, 1),
0402 BPF_EXIT_INSN(),
0403
0404 },
0405 .attach_type = BPF_CGROUP_SETSOCKOPT,
0406 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
0407 .error = DENY_ATTACH,
0408 },
0409 {
0410 .descr = "setsockopt: bypass bpf hook",
0411 .insns = {
0412
0413 BPF_MOV64_IMM(BPF_REG_0, 1),
0414 BPF_EXIT_INSN(),
0415 },
0416 .attach_type = BPF_CGROUP_SETSOCKOPT,
0417 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0418
0419 .get_level = SOL_IP,
0420 .set_level = SOL_IP,
0421
0422 .get_optname = IP_TOS,
0423 .set_optname = IP_TOS,
0424
0425 .set_optval = { 1 << 3 },
0426 .set_optlen = 1,
0427
0428 .get_optval = { 1 << 3 },
0429 .get_optlen = 1,
0430 },
0431 {
0432 .descr = "setsockopt: return EPERM from bpf hook",
0433 .insns = {
0434
0435 BPF_MOV64_IMM(BPF_REG_0, 0),
0436 BPF_EXIT_INSN(),
0437 },
0438 .attach_type = BPF_CGROUP_SETSOCKOPT,
0439 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0440
0441 .set_level = SOL_IP,
0442 .set_optname = IP_TOS,
0443
0444 .set_optlen = 1,
0445 .error = EPERM_SETSOCKOPT,
0446 },
0447 {
0448 .descr = "setsockopt: no optval bounds check, deny loading",
0449 .insns = {
0450
0451 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
0452 offsetof(struct bpf_sockopt, optval)),
0453
0454
0455 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6, 0),
0456
0457
0458 BPF_MOV64_IMM(BPF_REG_0, 1),
0459 BPF_EXIT_INSN(),
0460 },
0461 .attach_type = BPF_CGROUP_SETSOCKOPT,
0462 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0463 .error = DENY_LOAD,
0464 },
0465 {
0466 .descr = "setsockopt: read ctx->level",
0467 .insns = {
0468
0469 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
0470 offsetof(struct bpf_sockopt, level)),
0471
0472
0473 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
0474
0475 BPF_MOV64_IMM(BPF_REG_0, -1),
0476 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0477 offsetof(struct bpf_sockopt, optlen)),
0478
0479 BPF_MOV64_IMM(BPF_REG_0, 1),
0480 BPF_JMP_A(1),
0481
0482
0483 BPF_MOV64_IMM(BPF_REG_0, 0),
0484
0485 BPF_EXIT_INSN(),
0486 },
0487 .attach_type = BPF_CGROUP_SETSOCKOPT,
0488 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0489
0490 .set_level = 123,
0491
0492 .set_optlen = 1,
0493 },
0494 {
0495 .descr = "setsockopt: allow changing ctx->level",
0496 .insns = {
0497
0498 BPF_MOV64_IMM(BPF_REG_0, SOL_IP),
0499 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0500 offsetof(struct bpf_sockopt, level)),
0501
0502 BPF_MOV64_IMM(BPF_REG_0, 1),
0503 BPF_EXIT_INSN(),
0504 },
0505 .attach_type = BPF_CGROUP_SETSOCKOPT,
0506 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0507
0508 .get_level = SOL_IP,
0509 .set_level = 234,
0510
0511 .get_optname = IP_TOS,
0512 .set_optname = IP_TOS,
0513
0514 .set_optval = { 1 << 3 },
0515 .set_optlen = 1,
0516 .get_optval = { 1 << 3 },
0517 .get_optlen = 1,
0518 },
0519 {
0520 .descr = "setsockopt: read ctx->optname",
0521 .insns = {
0522
0523 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
0524 offsetof(struct bpf_sockopt, optname)),
0525
0526
0527 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
0528
0529 BPF_MOV64_IMM(BPF_REG_0, -1),
0530 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0531 offsetof(struct bpf_sockopt, optlen)),
0532
0533 BPF_MOV64_IMM(BPF_REG_0, 1),
0534 BPF_JMP_A(1),
0535
0536
0537 BPF_MOV64_IMM(BPF_REG_0, 0),
0538
0539 BPF_EXIT_INSN(),
0540 },
0541 .attach_type = BPF_CGROUP_SETSOCKOPT,
0542 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0543
0544 .set_optname = 123,
0545
0546 .set_optlen = 1,
0547 },
0548 {
0549 .descr = "setsockopt: allow changing ctx->optname",
0550 .insns = {
0551
0552 BPF_MOV64_IMM(BPF_REG_0, IP_TOS),
0553 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0554 offsetof(struct bpf_sockopt, optname)),
0555
0556 BPF_MOV64_IMM(BPF_REG_0, 1),
0557 BPF_EXIT_INSN(),
0558 },
0559 .attach_type = BPF_CGROUP_SETSOCKOPT,
0560 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0561
0562 .get_level = SOL_IP,
0563 .set_level = SOL_IP,
0564
0565 .get_optname = IP_TOS,
0566 .set_optname = 456,
0567
0568 .set_optval = { 1 << 3 },
0569 .set_optlen = 1,
0570 .get_optval = { 1 << 3 },
0571 .get_optlen = 1,
0572 },
0573 {
0574 .descr = "setsockopt: read ctx->optlen",
0575 .insns = {
0576
0577 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
0578 offsetof(struct bpf_sockopt, optlen)),
0579
0580
0581 BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4),
0582
0583 BPF_MOV64_IMM(BPF_REG_0, -1),
0584 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0585 offsetof(struct bpf_sockopt, optlen)),
0586
0587 BPF_MOV64_IMM(BPF_REG_0, 1),
0588 BPF_JMP_A(1),
0589
0590
0591 BPF_MOV64_IMM(BPF_REG_0, 0),
0592
0593 BPF_EXIT_INSN(),
0594 },
0595 .attach_type = BPF_CGROUP_SETSOCKOPT,
0596 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0597
0598 .set_optlen = 64,
0599 },
0600 {
0601 .descr = "setsockopt: ctx->optlen == -1 is ok",
0602 .insns = {
0603
0604 BPF_MOV64_IMM(BPF_REG_0, -1),
0605 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0606 offsetof(struct bpf_sockopt, optlen)),
0607
0608 BPF_MOV64_IMM(BPF_REG_0, 1),
0609 BPF_EXIT_INSN(),
0610 },
0611 .attach_type = BPF_CGROUP_SETSOCKOPT,
0612 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0613
0614 .set_optlen = 64,
0615 },
0616 {
0617 .descr = "setsockopt: deny ctx->optlen < 0 (except -1)",
0618 .insns = {
0619
0620 BPF_MOV64_IMM(BPF_REG_0, -2),
0621 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0622 offsetof(struct bpf_sockopt, optlen)),
0623
0624 BPF_MOV64_IMM(BPF_REG_0, 1),
0625 BPF_EXIT_INSN(),
0626 },
0627 .attach_type = BPF_CGROUP_SETSOCKOPT,
0628 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0629
0630 .set_optlen = 4,
0631
0632 .error = EFAULT_SETSOCKOPT,
0633 },
0634 {
0635 .descr = "setsockopt: deny ctx->optlen > input optlen",
0636 .insns = {
0637
0638 BPF_MOV64_IMM(BPF_REG_0, 65),
0639 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0640 offsetof(struct bpf_sockopt, optlen)),
0641 BPF_MOV64_IMM(BPF_REG_0, 1),
0642 BPF_EXIT_INSN(),
0643 },
0644 .attach_type = BPF_CGROUP_SETSOCKOPT,
0645 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0646
0647 .set_optlen = 64,
0648
0649 .error = EFAULT_SETSOCKOPT,
0650 },
0651 {
0652 .descr = "setsockopt: allow changing ctx->optlen within bounds",
0653 .insns = {
0654
0655 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
0656 offsetof(struct bpf_sockopt, optval)),
0657
0658 BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
0659
0660 BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),
0661
0662
0663 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,
0664 offsetof(struct bpf_sockopt, optval_end)),
0665
0666
0667 BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),
0668
0669 BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 1 << 3),
0670
0671
0672
0673 BPF_MOV64_IMM(BPF_REG_0, 1),
0674 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0675 offsetof(struct bpf_sockopt, optlen)),
0676
0677
0678 BPF_MOV64_IMM(BPF_REG_0, 1),
0679 BPF_EXIT_INSN(),
0680 },
0681 .attach_type = BPF_CGROUP_SETSOCKOPT,
0682 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0683
0684 .get_level = SOL_IP,
0685 .set_level = SOL_IP,
0686
0687 .get_optname = IP_TOS,
0688 .set_optname = IP_TOS,
0689
0690 .set_optval = { 1, 1, 1, 1 },
0691 .set_optlen = 4,
0692 .get_optval = { 1 << 3 },
0693 .get_optlen = 1,
0694 },
0695 {
0696 .descr = "setsockopt: deny write ctx->retval",
0697 .insns = {
0698
0699 BPF_MOV64_IMM(BPF_REG_0, 0),
0700 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
0701 offsetof(struct bpf_sockopt, retval)),
0702
0703
0704 BPF_MOV64_IMM(BPF_REG_0, 1),
0705 BPF_EXIT_INSN(),
0706 },
0707 .attach_type = BPF_CGROUP_SETSOCKOPT,
0708 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0709
0710 .error = DENY_LOAD,
0711 },
0712 {
0713 .descr = "setsockopt: deny read ctx->retval",
0714 .insns = {
0715
0716 BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
0717 offsetof(struct bpf_sockopt, retval)),
0718
0719
0720 BPF_MOV64_IMM(BPF_REG_0, 1),
0721 BPF_EXIT_INSN(),
0722 },
0723 .attach_type = BPF_CGROUP_SETSOCKOPT,
0724 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0725
0726 .error = DENY_LOAD,
0727 },
0728 {
0729 .descr = "setsockopt: deny writing to ctx->optval",
0730 .insns = {
0731
0732 BPF_MOV64_IMM(BPF_REG_0, 1),
0733 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
0734 offsetof(struct bpf_sockopt, optval)),
0735 BPF_EXIT_INSN(),
0736 },
0737 .attach_type = BPF_CGROUP_SETSOCKOPT,
0738 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0739
0740 .error = DENY_LOAD,
0741 },
0742 {
0743 .descr = "setsockopt: deny writing to ctx->optval_end",
0744 .insns = {
0745
0746 BPF_MOV64_IMM(BPF_REG_0, 1),
0747 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
0748 offsetof(struct bpf_sockopt, optval_end)),
0749 BPF_EXIT_INSN(),
0750 },
0751 .attach_type = BPF_CGROUP_SETSOCKOPT,
0752 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0753
0754 .error = DENY_LOAD,
0755 },
0756 {
0757 .descr = "setsockopt: allow IP_TOS <= 128",
0758 .insns = {
0759
0760 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
0761 offsetof(struct bpf_sockopt, optval)),
0762
0763 BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
0764 BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
0765
0766
0767 BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1,
0768 offsetof(struct bpf_sockopt, optval_end)),
0769
0770
0771 BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4),
0772
0773
0774 BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0),
0775
0776
0777 BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2),
0778 BPF_MOV64_IMM(BPF_REG_0, 1),
0779 BPF_JMP_A(1),
0780
0781
0782
0783 BPF_MOV64_IMM(BPF_REG_0, 0),
0784
0785
0786 BPF_EXIT_INSN(),
0787 },
0788 .attach_type = BPF_CGROUP_SETSOCKOPT,
0789 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0790
0791 .get_level = SOL_IP,
0792 .set_level = SOL_IP,
0793
0794 .get_optname = IP_TOS,
0795 .set_optname = IP_TOS,
0796
0797 .set_optval = { 0x80 },
0798 .set_optlen = 1,
0799 .get_optval = { 0x80 },
0800 .get_optlen = 1,
0801 },
0802 {
0803 .descr = "setsockopt: deny IP_TOS > 128",
0804 .insns = {
0805
0806 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
0807 offsetof(struct bpf_sockopt, optval)),
0808
0809 BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
0810 BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
0811
0812
0813 BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1,
0814 offsetof(struct bpf_sockopt, optval_end)),
0815
0816
0817 BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4),
0818
0819
0820 BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0),
0821
0822
0823 BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2),
0824 BPF_MOV64_IMM(BPF_REG_0, 1),
0825 BPF_JMP_A(1),
0826
0827
0828
0829 BPF_MOV64_IMM(BPF_REG_0, 0),
0830
0831
0832 BPF_EXIT_INSN(),
0833 },
0834 .attach_type = BPF_CGROUP_SETSOCKOPT,
0835 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
0836
0837 .get_level = SOL_IP,
0838 .set_level = SOL_IP,
0839
0840 .get_optname = IP_TOS,
0841 .set_optname = IP_TOS,
0842
0843 .set_optval = { 0x81 },
0844 .set_optlen = 1,
0845 .get_optval = { 0x00 },
0846 .get_optlen = 1,
0847
0848 .error = EPERM_SETSOCKOPT,
0849 },
0850 };
0851
0852 static int load_prog(const struct bpf_insn *insns,
0853 enum bpf_attach_type expected_attach_type)
0854 {
0855 LIBBPF_OPTS(bpf_prog_load_opts, opts,
0856 .expected_attach_type = expected_attach_type,
0857 .log_level = 2,
0858 .log_buf = bpf_log_buf,
0859 .log_size = sizeof(bpf_log_buf),
0860 );
0861 int fd, insns_cnt = 0;
0862
0863 for (;
0864 insns[insns_cnt].code != (BPF_JMP | BPF_EXIT);
0865 insns_cnt++) {
0866 }
0867 insns_cnt++;
0868
0869 fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCKOPT, NULL, "GPL", insns, insns_cnt, &opts);
0870 if (verbose && fd < 0)
0871 fprintf(stderr, "%s\n", bpf_log_buf);
0872
0873 return fd;
0874 }
0875
0876 static int run_test(int cgroup_fd, struct sockopt_test *test)
0877 {
0878 int sock_fd, err, prog_fd;
0879 void *optval = NULL;
0880 int ret = 0;
0881
0882 prog_fd = load_prog(test->insns, test->expected_attach_type);
0883 if (prog_fd < 0) {
0884 if (test->error == DENY_LOAD)
0885 return 0;
0886
0887 log_err("Failed to load BPF program");
0888 return -1;
0889 }
0890
0891 err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0);
0892 if (err < 0) {
0893 if (test->error == DENY_ATTACH)
0894 goto close_prog_fd;
0895
0896 log_err("Failed to attach BPF program");
0897 ret = -1;
0898 goto close_prog_fd;
0899 }
0900
0901 sock_fd = socket(AF_INET, SOCK_STREAM, 0);
0902 if (sock_fd < 0) {
0903 log_err("Failed to create AF_INET socket");
0904 ret = -1;
0905 goto detach_prog;
0906 }
0907
0908 if (test->set_optlen) {
0909 err = setsockopt(sock_fd, test->set_level, test->set_optname,
0910 test->set_optval, test->set_optlen);
0911 if (err) {
0912 if (errno == EPERM && test->error == EPERM_SETSOCKOPT)
0913 goto close_sock_fd;
0914 if (errno == EFAULT && test->error == EFAULT_SETSOCKOPT)
0915 goto free_optval;
0916
0917 log_err("Failed to call setsockopt");
0918 ret = -1;
0919 goto close_sock_fd;
0920 }
0921 }
0922
0923 if (test->get_optlen) {
0924 optval = malloc(test->get_optlen);
0925 socklen_t optlen = test->get_optlen;
0926 socklen_t expected_get_optlen = test->get_optlen_ret ?:
0927 test->get_optlen;
0928
0929 err = getsockopt(sock_fd, test->get_level, test->get_optname,
0930 optval, &optlen);
0931 if (err) {
0932 if (errno == EPERM && test->error == EPERM_GETSOCKOPT)
0933 goto free_optval;
0934 if (errno == EFAULT && test->error == EFAULT_GETSOCKOPT)
0935 goto free_optval;
0936
0937 log_err("Failed to call getsockopt");
0938 ret = -1;
0939 goto free_optval;
0940 }
0941
0942 if (optlen != expected_get_optlen) {
0943 errno = 0;
0944 log_err("getsockopt returned unexpected optlen");
0945 ret = -1;
0946 goto free_optval;
0947 }
0948
0949 if (memcmp(optval, test->get_optval, optlen) != 0) {
0950 errno = 0;
0951 log_err("getsockopt returned unexpected optval");
0952 ret = -1;
0953 goto free_optval;
0954 }
0955 }
0956
0957 ret = test->error != OK;
0958
0959 free_optval:
0960 free(optval);
0961 close_sock_fd:
0962 close(sock_fd);
0963 detach_prog:
0964 bpf_prog_detach2(prog_fd, cgroup_fd, test->attach_type);
0965 close_prog_fd:
0966 close(prog_fd);
0967 return ret;
0968 }
0969
0970 void test_sockopt(void)
0971 {
0972 int cgroup_fd, i;
0973
0974 cgroup_fd = test__join_cgroup("/sockopt");
0975 if (CHECK_FAIL(cgroup_fd < 0))
0976 return;
0977
0978 for (i = 0; i < ARRAY_SIZE(tests); i++) {
0979 test__start_subtest(tests[i].descr);
0980 CHECK_FAIL(run_test(cgroup_fd, &tests[i]));
0981 }
0982
0983 close(cgroup_fd);
0984 }