Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'Retire test_sock.c'

Jordan Rife says:

====================
This patch series migrates test cases out of test_sock.c to
prog_tests-style tests. It moves all BPF_CGROUP_INET4_POST_BIND and
BPF_CGROUP_INET6_POST_BIND test cases into a new prog_test,
sock_post_bind.c, while reimplementing all LOAD_REJECT test cases as
verifier tests in progs/verifier_sock.c. Finally, it moves remaining
BPF_CGROUP_INET_SOCK_CREATE test coverage into prog_tests/sock_create.c
before retiring test_sock.c completely.

Changes
=======
v1->v2:
- Remove superfluous verbose bool from the top of sock_post_bind.c.
- Use ASSERT_OK_FD instead of ASSERT_GE to test cgroup_fd validity.
- Run sock_post_bind tests in their own namespace, "sock_post_bind".
====================

Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>

+147 -204
-1
tools/testing/selftests/bpf/.gitignore
··· 16 16 /test_progs-cpuv4 17 17 test_verifier_log 18 18 feature 19 - test_sock 20 19 urandom_read 21 20 test_sockmap 22 21 test_lirc_mode2_user
+1 -2
tools/testing/selftests/bpf/Makefile
··· 84 84 85 85 # Order correspond to 'make run_tests' order 86 86 TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ 87 - test_sock test_sockmap \ 87 + test_sockmap \ 88 88 test_tcpnotify_user test_sysctl \ 89 89 test_progs-no_alu32 90 90 TEST_INST_SUBDIRS := no_alu32 ··· 335 335 CAP_HELPERS := $(OUTPUT)/cap_helpers.o 336 336 NETWORK_HELPERS := $(OUTPUT)/network_helpers.o 337 337 338 - $(OUTPUT)/test_sock: $(CGROUP_HELPERS) $(TESTING_HELPERS) 339 338 $(OUTPUT)/test_sockmap: $(CGROUP_HELPERS) $(TESTING_HELPERS) 340 339 $(OUTPUT)/test_tcpnotify_user: $(CGROUP_HELPERS) $(TESTING_HELPERS) $(TRACE_HELPERS) 341 340 $(OUTPUT)/test_sock_fields: $(CGROUP_HELPERS) $(TESTING_HELPERS)
+24 -9
tools/testing/selftests/bpf/prog_tests/sock_create.c
··· 237 237 238 238 .error = DENY_CREATE, 239 239 }, 240 + { 241 + .descr = "load w/o expected_attach_type (compat mode)", 242 + .insns = { 243 + /* return 1 */ 244 + BPF_MOV64_IMM(BPF_REG_0, 1), 245 + BPF_EXIT_INSN(), 246 + }, 247 + .expected_attach_type = 0, 248 + .attach_type = BPF_CGROUP_INET_SOCK_CREATE, 249 + 250 + .domain = AF_INET, 251 + .type = SOCK_STREAM, 252 + }, 240 253 }; 241 254 242 255 static int load_prog(const struct bpf_insn *insns, ··· 304 291 goto detach_prog; 305 292 } 306 293 307 - err = getsockopt(sock_fd, SOL_SOCKET, test->optname, &optval, &optlen); 308 - if (err) { 309 - log_err("Failed to call getsockopt"); 310 - goto cleanup; 311 - } 294 + if (test->optname) { 295 + err = getsockopt(sock_fd, SOL_SOCKET, test->optname, &optval, &optlen); 296 + if (err) { 297 + log_err("Failed to call getsockopt"); 298 + goto cleanup; 299 + } 312 300 313 - if (optval != test->optval) { 314 - errno = 0; 315 - log_err("getsockopt returned unexpected optval"); 316 - goto cleanup; 301 + if (optval != test->optval) { 302 + errno = 0; 303 + log_err("getsockopt returned unexpected optval"); 304 + goto cleanup; 305 + } 317 306 } 318 307 319 308 ret = test->error != OK;
+60
tools/testing/selftests/bpf/progs/verifier_sock.c
··· 977 977 : __clobber_all); 978 978 } 979 979 980 + SEC("cgroup/post_bind4") 981 + __description("sk->src_ip6[0] [load 1st byte]") 982 + __failure __msg("invalid bpf_context access off=28 size=2") 983 + __naked void post_bind4_read_src_ip6(void) 984 + { 985 + asm volatile (" \ 986 + r6 = r1; \ 987 + r7 = *(u16*)(r6 + %[bpf_sock_src_ip6_0]); \ 988 + r0 = 1; \ 989 + exit; \ 990 + " : 991 + : __imm_const(bpf_sock_src_ip6_0, offsetof(struct bpf_sock, src_ip6[0])) 992 + : __clobber_all); 993 + } 994 + 995 + SEC("cgroup/post_bind4") 996 + __description("sk->mark [load mark]") 997 + __failure __msg("invalid bpf_context access off=16 size=2") 998 + __naked void post_bind4_read_mark(void) 999 + { 1000 + asm volatile (" \ 1001 + r6 = r1; \ 1002 + r7 = *(u16*)(r6 + %[bpf_sock_mark]); \ 1003 + r0 = 1; \ 1004 + exit; \ 1005 + " : 1006 + : __imm_const(bpf_sock_mark, offsetof(struct bpf_sock, mark)) 1007 + : __clobber_all); 1008 + } 1009 + 1010 + SEC("cgroup/post_bind6") 1011 + __description("sk->src_ip4 [load src_ip4]") 1012 + __failure __msg("invalid bpf_context access off=24 size=2") 1013 + __naked void post_bind6_read_src_ip4(void) 1014 + { 1015 + asm volatile (" \ 1016 + r6 = r1; \ 1017 + r7 = *(u16*)(r6 + %[bpf_sock_src_ip4]); \ 1018 + r0 = 1; \ 1019 + exit; \ 1020 + " : 1021 + : __imm_const(bpf_sock_src_ip4, offsetof(struct bpf_sock, src_ip4)) 1022 + : __clobber_all); 1023 + } 1024 + 1025 + SEC("cgroup/sock_create") 1026 + __description("sk->src_port [word load]") 1027 + __failure __msg("invalid bpf_context access off=44 size=2") 1028 + __naked void sock_create_read_src_port(void) 1029 + { 1030 + asm volatile (" \ 1031 + r6 = r1; \ 1032 + r7 = *(u16*)(r6 + %[bpf_sock_src_port]); \ 1033 + r0 = 1; \ 1034 + exit; \ 1035 + " : 1036 + : __imm_const(bpf_sock_src_port, offsetof(struct bpf_sock, src_port)) 1037 + : __clobber_all); 1038 + } 1039 + 980 1040 char _license[] SEC("license") = "GPL";
+62 -192
tools/testing/selftests/bpf/test_sock.c tools/testing/selftests/bpf/prog_tests/sock_post_bind.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 - // Copyright (c) 2018 Facebook 3 - 4 - #include <stdio.h> 5 - #include <unistd.h> 6 - 7 - #include <arpa/inet.h> 8 - #include <sys/types.h> 9 - #include <sys/socket.h> 10 - 11 - #include <linux/filter.h> 12 - 13 - #include <bpf/bpf.h> 14 - 2 + #include <linux/bpf.h> 3 + #include <test_progs.h> 15 4 #include "cgroup_helpers.h" 16 - #include <bpf/bpf_endian.h> 17 - #include "bpf_util.h" 18 5 19 - #define CG_PATH "/foo" 20 - #define MAX_INSNS 512 6 + #define TEST_NS "sock_post_bind" 21 7 22 - char bpf_log_buf[BPF_LOG_BUF_SIZE]; 23 - static bool verbose = false; 8 + static char bpf_log_buf[4096]; 24 9 25 - struct sock_test { 26 - const char *descr; 10 + static struct sock_post_bind_test { 11 + const char *descr; 27 12 /* BPF prog properties */ 28 - struct bpf_insn insns[MAX_INSNS]; 29 - enum bpf_attach_type expected_attach_type; 30 - enum bpf_attach_type attach_type; 13 + const struct bpf_insn insns[64]; 14 + enum bpf_attach_type attach_type; 15 + enum bpf_attach_type expected_attach_type; 31 16 /* Socket properties */ 32 - int domain; 33 - int type; 17 + int domain; 18 + int type; 34 19 /* Endpoint to bind() to */ 35 20 const char *ip; 36 21 unsigned short port; 37 22 unsigned short port_retry; 23 + 38 24 /* Expected test result */ 39 25 enum { 40 - LOAD_REJECT, 41 26 ATTACH_REJECT, 42 27 BIND_REJECT, 43 28 SUCCESS, 44 29 RETRY_SUCCESS, 45 30 RETRY_REJECT 46 31 } result; 47 - }; 48 - 49 - static struct sock_test tests[] = { 50 - { 51 - .descr = "bind4 load with invalid access: src_ip6", 52 - .insns = { 53 - BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 54 - BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 55 - offsetof(struct bpf_sock, src_ip6[0])), 56 - BPF_MOV64_IMM(BPF_REG_0, 1), 57 - BPF_EXIT_INSN(), 58 - }, 59 - .expected_attach_type = BPF_CGROUP_INET4_POST_BIND, 60 - .attach_type = BPF_CGROUP_INET4_POST_BIND, 61 - .result = LOAD_REJECT, 62 - }, 63 - { 64 - .descr = "bind4 load with invalid access: mark", 65 - .insns = { 66 - BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 67 - BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 68 - offsetof(struct bpf_sock, mark)), 69 - BPF_MOV64_IMM(BPF_REG_0, 1), 70 - BPF_EXIT_INSN(), 71 - }, 72 - .expected_attach_type = BPF_CGROUP_INET4_POST_BIND, 73 - .attach_type = BPF_CGROUP_INET4_POST_BIND, 74 - .result = LOAD_REJECT, 75 - }, 76 - { 77 - .descr = "bind6 load with invalid access: src_ip4", 78 - .insns = { 79 - BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 80 - BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 81 - offsetof(struct bpf_sock, src_ip4)), 82 - BPF_MOV64_IMM(BPF_REG_0, 1), 83 - BPF_EXIT_INSN(), 84 - }, 85 - .expected_attach_type = BPF_CGROUP_INET6_POST_BIND, 86 - .attach_type = BPF_CGROUP_INET6_POST_BIND, 87 - .result = LOAD_REJECT, 88 - }, 89 - { 90 - .descr = "sock_create load with invalid access: src_port", 91 - .insns = { 92 - BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 93 - BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 94 - offsetof(struct bpf_sock, src_port)), 95 - BPF_MOV64_IMM(BPF_REG_0, 1), 96 - BPF_EXIT_INSN(), 97 - }, 98 - .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE, 99 - .attach_type = BPF_CGROUP_INET_SOCK_CREATE, 100 - .result = LOAD_REJECT, 101 - }, 102 - { 103 - .descr = "sock_create load w/o expected_attach_type (compat mode)", 104 - .insns = { 105 - BPF_MOV64_IMM(BPF_REG_0, 1), 106 - BPF_EXIT_INSN(), 107 - }, 108 - .expected_attach_type = 0, 109 - .attach_type = BPF_CGROUP_INET_SOCK_CREATE, 110 - .domain = AF_INET, 111 - .type = SOCK_STREAM, 112 - .ip = "127.0.0.1", 113 - .port = 8097, 114 - .result = SUCCESS, 115 - }, 116 - { 117 - .descr = "sock_create load w/ expected_attach_type", 118 - .insns = { 119 - BPF_MOV64_IMM(BPF_REG_0, 1), 120 - BPF_EXIT_INSN(), 121 - }, 122 - .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE, 123 - .attach_type = BPF_CGROUP_INET_SOCK_CREATE, 124 - .domain = AF_INET, 125 - .type = SOCK_STREAM, 126 - .ip = "127.0.0.1", 127 - .port = 8097, 128 - .result = SUCCESS, 129 - }, 32 + } tests[] = { 130 33 { 131 34 .descr = "attach type mismatch bind4 vs bind6", 132 35 .insns = { ··· 277 374 }, 278 375 }; 279 376 280 - static size_t probe_prog_length(const struct bpf_insn *fp) 377 + static int load_prog(const struct bpf_insn *insns, 378 + enum bpf_attach_type expected_attach_type) 281 379 { 282 - size_t len; 380 + LIBBPF_OPTS(bpf_prog_load_opts, opts, 381 + .expected_attach_type = expected_attach_type, 382 + .log_level = 2, 383 + .log_buf = bpf_log_buf, 384 + .log_size = sizeof(bpf_log_buf), 385 + ); 386 + int fd, insns_cnt = 0; 283 387 284 - for (len = MAX_INSNS - 1; len > 0; --len) 285 - if (fp[len].code != 0 || fp[len].imm != 0) 286 - break; 287 - return len + 1; 288 - } 388 + for (; 389 + insns[insns_cnt].code != (BPF_JMP | BPF_EXIT); 390 + insns_cnt++) { 391 + } 392 + insns_cnt++; 289 393 290 - static int load_sock_prog(const struct bpf_insn *prog, 291 - enum bpf_attach_type attach_type) 292 - { 293 - LIBBPF_OPTS(bpf_prog_load_opts, opts); 294 - int ret, insn_cnt; 295 - 296 - insn_cnt = probe_prog_length(prog); 297 - 298 - opts.expected_attach_type = attach_type; 299 - opts.log_buf = bpf_log_buf; 300 - opts.log_size = BPF_LOG_BUF_SIZE; 301 - opts.log_level = 2; 302 - 303 - ret = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", prog, insn_cnt, &opts); 304 - if (verbose && ret < 0) 394 + fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns, 395 + insns_cnt, &opts); 396 + if (fd < 0) 305 397 fprintf(stderr, "%s\n", bpf_log_buf); 306 398 307 - return ret; 308 - } 309 - 310 - static int attach_sock_prog(int cgfd, int progfd, 311 - enum bpf_attach_type attach_type) 312 - { 313 - return bpf_prog_attach(progfd, cgfd, attach_type, BPF_F_ALLOW_OVERRIDE); 399 + return fd; 314 400 } 315 401 316 402 static int bind_sock(int domain, int type, const char *ip, ··· 369 477 return res; 370 478 } 371 479 372 - static int run_test_case(int cgfd, const struct sock_test *test) 480 + static int run_test(int cgroup_fd, struct sock_post_bind_test *test) 373 481 { 374 - int progfd = -1; 375 - int err = 0; 376 - int res; 482 + int err, prog_fd, res, ret = 0; 377 483 378 - printf("Test case: %s .. ", test->descr); 379 - progfd = load_sock_prog(test->insns, test->expected_attach_type); 380 - if (progfd < 0) { 381 - if (test->result == LOAD_REJECT) 382 - goto out; 383 - else 384 - goto err; 385 - } 484 + prog_fd = load_prog(test->insns, test->expected_attach_type); 485 + if (prog_fd < 0) 486 + goto err; 386 487 387 - if (attach_sock_prog(cgfd, progfd, test->attach_type) < 0) { 488 + err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0); 489 + if (err < 0) { 388 490 if (test->result == ATTACH_REJECT) 389 491 goto out; 390 492 else ··· 389 503 test->port_retry); 390 504 if (res > 0 && test->result == res) 391 505 goto out; 392 - 393 506 err: 394 - err = -1; 507 + ret = -1; 395 508 out: 396 509 /* Detaching w/o checking return code: best effort attempt. */ 397 - if (progfd != -1) 398 - bpf_prog_detach(cgfd, test->attach_type); 399 - close(progfd); 400 - printf("[%s]\n", err ? "FAIL" : "PASS"); 401 - return err; 510 + if (prog_fd != -1) 511 + bpf_prog_detach(cgroup_fd, test->attach_type); 512 + close(prog_fd); 513 + return ret; 402 514 } 403 515 404 - static int run_tests(int cgfd) 516 + void test_sock_post_bind(void) 405 517 { 406 - int passes = 0; 407 - int fails = 0; 518 + struct netns_obj *ns; 519 + int cgroup_fd; 408 520 int i; 409 521 410 - for (i = 0; i < ARRAY_SIZE(tests); ++i) { 411 - if (run_test_case(cgfd, &tests[i])) 412 - ++fails; 413 - else 414 - ++passes; 522 + cgroup_fd = test__join_cgroup("/post_bind"); 523 + if (!ASSERT_OK_FD(cgroup_fd, "join_cgroup")) 524 + return; 525 + 526 + ns = netns_new(TEST_NS, true); 527 + if (!ASSERT_OK_PTR(ns, "netns_new")) 528 + goto cleanup; 529 + 530 + for (i = 0; i < ARRAY_SIZE(tests); i++) { 531 + if (!test__start_subtest(tests[i].descr)) 532 + continue; 533 + 534 + ASSERT_OK(run_test(cgroup_fd, &tests[i]), tests[i].descr); 415 535 } 416 - printf("Summary: %d PASSED, %d FAILED\n", passes, fails); 417 - return fails ? -1 : 0; 418 - } 419 536 420 - int main(int argc, char **argv) 421 - { 422 - int cgfd = -1; 423 - int err = 0; 424 - 425 - cgfd = cgroup_setup_and_join(CG_PATH); 426 - if (cgfd < 0) 427 - goto err; 428 - 429 - /* Use libbpf 1.0 API mode */ 430 - libbpf_set_strict_mode(LIBBPF_STRICT_ALL); 431 - 432 - if (run_tests(cgfd)) 433 - goto err; 434 - 435 - goto out; 436 - err: 437 - err = -1; 438 - out: 439 - close(cgfd); 440 - cleanup_cgroup_environment(); 441 - return err; 537 + cleanup: 538 + netns_free(ns); 539 + close(cgroup_fd); 442 540 }