1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 #include "test_attach_probe.skel.h" 4 5 /* this is how USDT semaphore is actually defined, except volatile modifier */ 6 volatile unsigned short uprobe_ref_ctr __attribute__((unused)) __attribute((section(".probes"))); 7 8 /* uprobe attach point */ 9 static void trigger_func(void) 10 { 11 asm volatile (""); 12 } 13 14 /* attach point for byname uprobe */ 15 static void trigger_func2(void) 16 { 17 asm volatile (""); 18 } 19 20 /* attach point for byname sleepable uprobe */ 21 static void trigger_func3(void) 22 { 23 asm volatile (""); 24 } 25 26 static char test_data[] = "test_data"; 27 28 void test_attach_probe(void) 29 { 30 DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts); 31 struct bpf_link *kprobe_link, *kretprobe_link; 32 struct bpf_link *uprobe_link, *uretprobe_link; 33 struct test_attach_probe* skel; 34 ssize_t uprobe_offset, ref_ctr_offset; 35 struct bpf_link *uprobe_err_link; 36 bool legacy; 37 char *mem; 38 39 /* Check if new-style kprobe/uprobe API is supported. 40 * Kernels that support new FD-based kprobe and uprobe BPF attachment 41 * through perf_event_open() syscall expose 42 * /sys/bus/event_source/devices/kprobe/type and 43 * /sys/bus/event_source/devices/uprobe/type files, respectively. They 44 * contain magic numbers that are passed as "type" field of 45 * perf_event_attr. Lack of such file in the system indicates legacy 46 * kernel with old-style kprobe/uprobe attach interface through 47 * creating per-probe event through tracefs. For such cases 48 * ref_ctr_offset feature is not supported, so we don't test it. 49 */ 50 legacy = access("/sys/bus/event_source/devices/kprobe/type", F_OK) != 0; 51 52 uprobe_offset = get_uprobe_offset(&trigger_func); 53 if (!ASSERT_GE(uprobe_offset, 0, "uprobe_offset")) 54 return; 55 56 ref_ctr_offset = get_rel_offset((uintptr_t)&uprobe_ref_ctr); 57 if (!ASSERT_GE(ref_ctr_offset, 0, "ref_ctr_offset")) 58 return; 59 60 skel = test_attach_probe__open(); 61 if (!ASSERT_OK_PTR(skel, "skel_open")) 62 return; 63 64 /* sleepable kprobe test case needs flags set before loading */ 65 if (!ASSERT_OK(bpf_program__set_flags(skel->progs.handle_kprobe_sleepable, 66 BPF_F_SLEEPABLE), "kprobe_sleepable_flags")) 67 goto cleanup; 68 69 if (!ASSERT_OK(test_attach_probe__load(skel), "skel_load")) 70 goto cleanup; 71 if (!ASSERT_OK_PTR(skel->bss, "check_bss")) 72 goto cleanup; 73 74 /* manual-attach kprobe/kretprobe */ 75 kprobe_link = bpf_program__attach_kprobe(skel->progs.handle_kprobe, 76 false /* retprobe */, 77 SYS_NANOSLEEP_KPROBE_NAME); 78 if (!ASSERT_OK_PTR(kprobe_link, "attach_kprobe")) 79 goto cleanup; 80 skel->links.handle_kprobe = kprobe_link; 81 82 kretprobe_link = bpf_program__attach_kprobe(skel->progs.handle_kretprobe, 83 true /* retprobe */, 84 SYS_NANOSLEEP_KPROBE_NAME); 85 if (!ASSERT_OK_PTR(kretprobe_link, "attach_kretprobe")) 86 goto cleanup; 87 skel->links.handle_kretprobe = kretprobe_link; 88 89 /* auto-attachable kprobe and kretprobe */ 90 skel->links.handle_kprobe_auto = bpf_program__attach(skel->progs.handle_kprobe_auto); 91 ASSERT_OK_PTR(skel->links.handle_kprobe_auto, "attach_kprobe_auto"); 92 93 skel->links.handle_kretprobe_auto = bpf_program__attach(skel->progs.handle_kretprobe_auto); 94 ASSERT_OK_PTR(skel->links.handle_kretprobe_auto, "attach_kretprobe_auto"); 95 96 if (!legacy) 97 ASSERT_EQ(uprobe_ref_ctr, 0, "uprobe_ref_ctr_before"); 98 99 uprobe_opts.retprobe = false; 100 uprobe_opts.ref_ctr_offset = legacy ? 0 : ref_ctr_offset; 101 uprobe_link = bpf_program__attach_uprobe_opts(skel->progs.handle_uprobe, 102 0 /* self pid */, 103 "/proc/self/exe", 104 uprobe_offset, 105 &uprobe_opts); 106 if (!ASSERT_OK_PTR(uprobe_link, "attach_uprobe")) 107 goto cleanup; 108 skel->links.handle_uprobe = uprobe_link; 109 110 if (!legacy) 111 ASSERT_GT(uprobe_ref_ctr, 0, "uprobe_ref_ctr_after"); 112 113 /* if uprobe uses ref_ctr, uretprobe has to use ref_ctr as well */ 114 uprobe_opts.retprobe = true; 115 uprobe_opts.ref_ctr_offset = legacy ? 0 : ref_ctr_offset; 116 uretprobe_link = bpf_program__attach_uprobe_opts(skel->progs.handle_uretprobe, 117 -1 /* any pid */, 118 "/proc/self/exe", 119 uprobe_offset, &uprobe_opts); 120 if (!ASSERT_OK_PTR(uretprobe_link, "attach_uretprobe")) 121 goto cleanup; 122 skel->links.handle_uretprobe = uretprobe_link; 123 124 /* verify auto-attach fails for old-style uprobe definition */ 125 uprobe_err_link = bpf_program__attach(skel->progs.handle_uprobe_byname); 126 if (!ASSERT_EQ(libbpf_get_error(uprobe_err_link), -EOPNOTSUPP, 127 "auto-attach should fail for old-style name")) 128 goto cleanup; 129 130 uprobe_opts.func_name = "trigger_func2"; 131 uprobe_opts.retprobe = false; 132 uprobe_opts.ref_ctr_offset = 0; 133 skel->links.handle_uprobe_byname = 134 bpf_program__attach_uprobe_opts(skel->progs.handle_uprobe_byname, 135 0 /* this pid */, 136 "/proc/self/exe", 137 0, &uprobe_opts); 138 if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname, "attach_uprobe_byname")) 139 goto cleanup; 140 141 /* verify auto-attach works */ 142 skel->links.handle_uretprobe_byname = 143 bpf_program__attach(skel->progs.handle_uretprobe_byname); 144 if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname, "attach_uretprobe_byname")) 145 goto cleanup; 146 147 /* test attach by name for a library function, using the library 148 * as the binary argument. libc.so.6 will be resolved via dlopen()/dlinfo(). 149 */ 150 uprobe_opts.func_name = "malloc"; 151 uprobe_opts.retprobe = false; 152 skel->links.handle_uprobe_byname2 = 153 bpf_program__attach_uprobe_opts(skel->progs.handle_uprobe_byname2, 154 0 /* this pid */, 155 "libc.so.6", 156 0, &uprobe_opts); 157 if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname2, "attach_uprobe_byname2")) 158 goto cleanup; 159 160 uprobe_opts.func_name = "free"; 161 uprobe_opts.retprobe = true; 162 skel->links.handle_uretprobe_byname2 = 163 bpf_program__attach_uprobe_opts(skel->progs.handle_uretprobe_byname2, 164 -1 /* any pid */, 165 "libc.so.6", 166 0, &uprobe_opts); 167 if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname2, "attach_uretprobe_byname2")) 168 goto cleanup; 169 170 /* sleepable kprobes should not attach successfully */ 171 skel->links.handle_kprobe_sleepable = bpf_program__attach(skel->progs.handle_kprobe_sleepable); 172 if (!ASSERT_ERR_PTR(skel->links.handle_kprobe_sleepable, "attach_kprobe_sleepable")) 173 goto cleanup; 174 175 /* test sleepable uprobe and uretprobe variants */ 176 skel->links.handle_uprobe_byname3_sleepable = bpf_program__attach(skel->progs.handle_uprobe_byname3_sleepable); 177 if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname3_sleepable, "attach_uprobe_byname3_sleepable")) 178 goto cleanup; 179 180 skel->links.handle_uprobe_byname3 = bpf_program__attach(skel->progs.handle_uprobe_byname3); 181 if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname3, "attach_uprobe_byname3")) 182 goto cleanup; 183 184 skel->links.handle_uretprobe_byname3_sleepable = bpf_program__attach(skel->progs.handle_uretprobe_byname3_sleepable); 185 if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname3_sleepable, "attach_uretprobe_byname3_sleepable")) 186 goto cleanup; 187 188 skel->links.handle_uretprobe_byname3 = bpf_program__attach(skel->progs.handle_uretprobe_byname3); 189 if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname3, "attach_uretprobe_byname3")) 190 goto cleanup; 191 192 skel->bss->user_ptr = test_data; 193 194 /* trigger & validate kprobe && kretprobe */ 195 usleep(1); 196 197 /* trigger & validate shared library u[ret]probes attached by name */ 198 mem = malloc(1); 199 free(mem); 200 201 /* trigger & validate uprobe & uretprobe */ 202 trigger_func(); 203 204 /* trigger & validate uprobe attached by name */ 205 trigger_func2(); 206 207 /* trigger & validate sleepable uprobe attached by name */ 208 trigger_func3(); 209 210 ASSERT_EQ(skel->bss->kprobe_res, 1, "check_kprobe_res"); 211 ASSERT_EQ(skel->bss->kprobe2_res, 11, "check_kprobe_auto_res"); 212 ASSERT_EQ(skel->bss->kretprobe_res, 2, "check_kretprobe_res"); 213 ASSERT_EQ(skel->bss->kretprobe2_res, 22, "check_kretprobe_auto_res"); 214 ASSERT_EQ(skel->bss->uprobe_res, 3, "check_uprobe_res"); 215 ASSERT_EQ(skel->bss->uretprobe_res, 4, "check_uretprobe_res"); 216 ASSERT_EQ(skel->bss->uprobe_byname_res, 5, "check_uprobe_byname_res"); 217 ASSERT_EQ(skel->bss->uretprobe_byname_res, 6, "check_uretprobe_byname_res"); 218 ASSERT_EQ(skel->bss->uprobe_byname2_res, 7, "check_uprobe_byname2_res"); 219 ASSERT_EQ(skel->bss->uretprobe_byname2_res, 8, "check_uretprobe_byname2_res"); 220 ASSERT_EQ(skel->bss->uprobe_byname3_sleepable_res, 9, "check_uprobe_byname3_sleepable_res"); 221 ASSERT_EQ(skel->bss->uprobe_byname3_res, 10, "check_uprobe_byname3_res"); 222 ASSERT_EQ(skel->bss->uretprobe_byname3_sleepable_res, 11, "check_uretprobe_byname3_sleepable_res"); 223 ASSERT_EQ(skel->bss->uretprobe_byname3_res, 12, "check_uretprobe_byname3_res"); 224 225 cleanup: 226 test_attach_probe__destroy(skel); 227 ASSERT_EQ(uprobe_ref_ctr, 0, "uprobe_ref_ctr_cleanup"); 228 } 229