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

selftests/bpf: add freplace of BTF-unreliable main prog test

Add a test validating that freplace'ing another main (entry) BPF program
fails if the target BPF program doesn't have valid/expected func proto BTF.

We extend fexit_bpf2bpf test to allow to specify expected log message
for negative test cases (where freplace program is expected to fail to
load).

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20231215011334.2307144-11-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
f0a50562 0a0ffcac

+69 -3
+27 -3
tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c
··· 348 348 } 349 349 350 350 static void test_obj_load_failure_common(const char *obj_file, 351 - const char *target_obj_file) 351 + const char *target_obj_file, 352 + const char *exp_msg) 352 353 { 353 354 /* 354 355 * standalone test that asserts failure to load freplace prog ··· 357 356 */ 358 357 struct bpf_object *obj = NULL, *pkt_obj; 359 358 struct bpf_program *prog; 359 + char log_buf[64 * 1024]; 360 360 int err, pkt_fd; 361 361 __u32 duration = 0; 362 362 ··· 376 374 err = bpf_program__set_attach_target(prog, pkt_fd, NULL); 377 375 ASSERT_OK(err, "set_attach_target"); 378 376 377 + log_buf[0] = '\0'; 378 + if (exp_msg) 379 + bpf_program__set_log_buf(prog, log_buf, sizeof(log_buf)); 380 + if (env.verbosity > VERBOSE_NONE) 381 + bpf_program__set_log_level(prog, 2); 382 + 379 383 /* It should fail to load the program */ 380 384 err = bpf_object__load(obj); 385 + if (env.verbosity > VERBOSE_NONE && exp_msg) /* we overtook log */ 386 + printf("VERIFIER LOG:\n================\n%s\n================\n", log_buf); 381 387 if (CHECK(!err, "bpf_obj_load should fail", "err %d\n", err)) 382 388 goto close_prog; 383 389 390 + if (exp_msg) 391 + ASSERT_HAS_SUBSTR(log_buf, exp_msg, "fail_msg"); 384 392 close_prog: 385 393 bpf_object__close(obj); 386 394 bpf_object__close(pkt_obj); ··· 400 388 { 401 389 /* test invalid return code in the replaced program */ 402 390 test_obj_load_failure_common("./freplace_connect_v4_prog.bpf.o", 403 - "./connect4_prog.bpf.o"); 391 + "./connect4_prog.bpf.o", NULL); 404 392 } 405 393 406 394 static void test_func_map_prog_compatibility(void) 407 395 { 408 396 /* test with spin lock map value in the replaced program */ 409 397 test_obj_load_failure_common("./freplace_attach_probe.bpf.o", 410 - "./test_attach_probe.bpf.o"); 398 + "./test_attach_probe.bpf.o", NULL); 399 + } 400 + 401 + static void test_func_replace_unreliable(void) 402 + { 403 + /* freplace'ing unreliable main prog should fail with error 404 + * "Cannot replace static functions" 405 + */ 406 + test_obj_load_failure_common("freplace_unreliable_prog.bpf.o", 407 + "./verifier_btf_unreliable_prog.bpf.o", 408 + "Cannot replace static functions"); 411 409 } 412 410 413 411 static void test_func_replace_global_func(void) ··· 585 563 test_func_replace_return_code(); 586 564 if (test__start_subtest("func_map_prog_compatibility")) 587 565 test_func_map_prog_compatibility(); 566 + if (test__start_subtest("func_replace_unreliable")) 567 + test_func_replace_unreliable(); 588 568 if (test__start_subtest("func_replace_multi")) 589 569 test_func_replace_multi(); 590 570 if (test__start_subtest("fmod_ret_freplace"))
+2
tools/testing/selftests/bpf/prog_tests/verifier.c
··· 14 14 #include "verifier_bpf_get_stack.skel.h" 15 15 #include "verifier_bswap.skel.h" 16 16 #include "verifier_btf_ctx_access.skel.h" 17 + #include "verifier_btf_unreliable_prog.skel.h" 17 18 #include "verifier_cfg.skel.h" 18 19 #include "verifier_cgroup_inv_retcode.skel.h" 19 20 #include "verifier_cgroup_skb.skel.h" ··· 126 125 void test_verifier_bpf_get_stack(void) { RUN(verifier_bpf_get_stack); } 127 126 void test_verifier_bswap(void) { RUN(verifier_bswap); } 128 127 void test_verifier_btf_ctx_access(void) { RUN(verifier_btf_ctx_access); } 128 + void test_verifier_btf_unreliable_prog(void) { RUN(verifier_btf_unreliable_prog); } 129 129 void test_verifier_cfg(void) { RUN(verifier_cfg); } 130 130 void test_verifier_cgroup_inv_retcode(void) { RUN(verifier_cgroup_inv_retcode); } 131 131 void test_verifier_cgroup_skb(void) { RUN(verifier_cgroup_skb); }
+20
tools/testing/selftests/bpf/progs/freplace_unreliable_prog.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (c) 2020 Facebook 3 + 4 + #include "vmlinux.h" 5 + #include <bpf/bpf_helpers.h> 6 + #include <bpf/bpf_tracing.h> 7 + 8 + SEC("freplace/btf_unreliable_kprobe") 9 + /* context type is what BPF verifier expects for kprobe context, but target 10 + * program has `stuct whatever *ctx` argument, so freplace operation will be 11 + * rejected with the following message: 12 + * 13 + * arg0 replace_btf_unreliable_kprobe(struct pt_regs *) doesn't match btf_unreliable_kprobe(struct whatever *) 14 + */ 15 + int replace_btf_unreliable_kprobe(bpf_user_pt_regs_t *ctx) 16 + { 17 + return 0; 18 + } 19 + 20 + char _license[] SEC("license") = "GPL";
+20
tools/testing/selftests/bpf/progs/verifier_btf_unreliable_prog.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (c) 2017 Facebook 3 + 4 + #include "vmlinux.h" 5 + #include <bpf/bpf_helpers.h> 6 + #include <bpf/bpf_tracing.h> 7 + #include <bpf/bpf_core_read.h> 8 + #include "bpf_misc.h" 9 + 10 + struct whatever {}; 11 + 12 + SEC("kprobe") 13 + __success __log_level(2) 14 + /* context type is wrong, making it impossible to freplace this program */ 15 + int btf_unreliable_kprobe(struct whatever *ctx) 16 + { 17 + return 0; 18 + } 19 + 20 + char _license[] SEC("license") = "GPL";