1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2022 Red Hat */ 3 #include <test_progs.h> 4 #include <bpf/btf.h> 5 #include "bpf/libbpf_internal.h" 6 #include "cgroup_helpers.h" 7 #include "bpf_util.h" 8 9 static const char *module_name = "bpf_testmod"; 10 static const char *symbol_name = "bpf_fentry_shadow_test"; 11 12 static int get_bpf_testmod_btf_fd(void) 13 { 14 struct bpf_btf_info info; 15 char name[64]; 16 __u32 id = 0, len; 17 int err, fd; 18 19 while (true) { 20 err = bpf_btf_get_next_id(id, &id); 21 if (err) { 22 log_err("failed to iterate BTF objects"); 23 return err; 24 } 25 26 fd = bpf_btf_get_fd_by_id(id); 27 if (fd < 0) { 28 if (errno == ENOENT) 29 continue; /* expected race: BTF was unloaded */ 30 err = -errno; 31 log_err("failed to get FD for BTF object #%d", id); 32 return err; 33 } 34 35 len = sizeof(info); 36 memset(&info, 0, sizeof(info)); 37 info.name = ptr_to_u64(name); 38 info.name_len = sizeof(name); 39 40 err = bpf_obj_get_info_by_fd(fd, &info, &len); 41 if (err) { 42 err = -errno; 43 log_err("failed to get info for BTF object #%d", id); 44 close(fd); 45 return err; 46 } 47 48 if (strcmp(name, module_name) == 0) 49 return fd; 50 51 close(fd); 52 } 53 return -ENOENT; 54 } 55 56 void test_module_fentry_shadow(void) 57 { 58 struct btf *vmlinux_btf = NULL, *mod_btf = NULL; 59 int err, i; 60 int btf_fd[2] = {}; 61 int prog_fd[2] = {}; 62 int link_fd[2] = {}; 63 __s32 btf_id[2] = {}; 64 65 if (!env.has_testmod) { 66 test__skip(); 67 return; 68 } 69 70 LIBBPF_OPTS(bpf_prog_load_opts, load_opts, 71 .expected_attach_type = BPF_TRACE_FENTRY, 72 ); 73 74 const struct bpf_insn trace_program[] = { 75 BPF_MOV64_IMM(BPF_REG_0, 0), 76 BPF_EXIT_INSN(), 77 }; 78 79 vmlinux_btf = btf__load_vmlinux_btf(); 80 if (!ASSERT_OK_PTR(vmlinux_btf, "load_vmlinux_btf")) 81 return; 82 83 btf_fd[1] = get_bpf_testmod_btf_fd(); 84 if (!ASSERT_GE(btf_fd[1], 0, "get_bpf_testmod_btf_fd")) 85 goto out; 86 87 mod_btf = btf_get_from_fd(btf_fd[1], vmlinux_btf); 88 if (!ASSERT_OK_PTR(mod_btf, "btf_get_from_fd")) 89 goto out; 90 91 btf_id[0] = btf__find_by_name_kind(vmlinux_btf, symbol_name, BTF_KIND_FUNC); 92 if (!ASSERT_GT(btf_id[0], 0, "btf_find_by_name")) 93 goto out; 94 95 btf_id[1] = btf__find_by_name_kind(mod_btf, symbol_name, BTF_KIND_FUNC); 96 if (!ASSERT_GT(btf_id[1], 0, "btf_find_by_name")) 97 goto out; 98 99 for (i = 0; i < 2; i++) { 100 load_opts.attach_btf_id = btf_id[i]; 101 load_opts.attach_btf_obj_fd = btf_fd[i]; 102 prog_fd[i] = bpf_prog_load(BPF_PROG_TYPE_TRACING, NULL, "GPL", 103 trace_program, 104 ARRAY_SIZE(trace_program), 105 &load_opts); 106 if (!ASSERT_GE(prog_fd[i], 0, "bpf_prog_load")) 107 goto out; 108 109 /* If the verifier incorrectly resolves addresses of the 110 * shadowed functions and uses the same address for both the 111 * vmlinux and the bpf_testmod functions, this will fail on 112 * attempting to create two trampolines for the same address, 113 * which is forbidden. 114 */ 115 link_fd[i] = bpf_link_create(prog_fd[i], 0, BPF_TRACE_FENTRY, NULL); 116 if (!ASSERT_GE(link_fd[i], 0, "bpf_link_create")) 117 goto out; 118 } 119 120 err = bpf_prog_test_run_opts(prog_fd[0], NULL); 121 ASSERT_OK(err, "running test"); 122 123 out: 124 btf__free(vmlinux_btf); 125 btf__free(mod_btf); 126 for (i = 0; i < 2; i++) { 127 if (btf_fd[i]) 128 close(btf_fd[i]); 129 if (prog_fd[i] > 0) 130 close(prog_fd[i]); 131 if (link_fd[i] > 0) 132 close(link_fd[i]); 133 } 134 } 135