1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2023 Yafang Shao <laoar.shao@gmail.com> */
3
4 #include <string.h>
5 #include <linux/bpf.h>
6 #include <linux/limits.h>
7 #include <bpf/btf.h>
8 #include <test_progs.h>
9 #include "trace_helpers.h"
10 #include "test_fill_link_info.skel.h"
11 #include "bpf/libbpf_internal.h"
12
13 #define TP_CAT "sched"
14 #define TP_NAME "sched_switch"
15
16 static const char *kmulti_syms[] = {
17 "bpf_fentry_test2",
18 "bpf_fentry_test1",
19 "bpf_fentry_test3",
20 };
21 #define KMULTI_CNT ARRAY_SIZE(kmulti_syms)
22 static __u64 kmulti_addrs[KMULTI_CNT];
23 static __u64 kmulti_cookies[] = { 3, 1, 2 };
24
25 #define KPROBE_FUNC "bpf_fentry_test1"
26 static __u64 kprobe_addr;
27
28 static const char * const tmulti_syms[] = {
29 "bpf_fentry_test2",
30 "bpf_fentry_test1",
31 "bpf_fentry_test3",
32 };
33
34 static __u64 tmulti_cookies[] = { 30, 10, 20 };
35 #define TRACING_MULTI_CNT ARRAY_SIZE(tmulti_syms)
36
37 struct tmulti_target {
38 const char *name;
39 __u64 addr;
40 __u64 cookie;
41 __u32 id;
42 };
43
44 #define UPROBE_FILE "/proc/self/exe"
45 static ssize_t uprobe_offset;
46 /* uprobe attach point */
uprobe_func(void)47 static noinline void uprobe_func(void)
48 {
49 asm volatile ("");
50 }
51
52 #define PERF_EVENT_COOKIE 0xdeadbeef
53
verify_perf_link_info(int fd,enum bpf_perf_event_type type,long addr,ssize_t offset,ssize_t entry_offset)54 static int verify_perf_link_info(int fd, enum bpf_perf_event_type type, long addr,
55 ssize_t offset, ssize_t entry_offset)
56 {
57 ssize_t ref_ctr_offset = entry_offset /* ref_ctr_offset for uprobes */;
58 struct bpf_link_info info;
59 __u32 len = sizeof(info);
60 char buf[PATH_MAX];
61 int err;
62
63 memset(&info, 0, sizeof(info));
64 buf[0] = '\0';
65
66 again:
67 err = bpf_link_get_info_by_fd(fd, &info, &len);
68 if (!ASSERT_OK(err, "get_link_info"))
69 return -1;
70
71 if (!ASSERT_EQ(info.type, BPF_LINK_TYPE_PERF_EVENT, "link_type"))
72 return -1;
73 if (!ASSERT_EQ(info.perf_event.type, type, "perf_type_match"))
74 return -1;
75
76 switch (info.perf_event.type) {
77 case BPF_PERF_EVENT_KPROBE:
78 case BPF_PERF_EVENT_KRETPROBE:
79 ASSERT_EQ(info.perf_event.kprobe.offset, offset, "kprobe_offset");
80
81 /* In case kernel.kptr_restrict is not permitted or MAX_SYMS is reached */
82 if (addr)
83 ASSERT_EQ(info.perf_event.kprobe.addr, addr + entry_offset,
84 "kprobe_addr");
85
86 ASSERT_EQ(info.perf_event.kprobe.cookie, PERF_EVENT_COOKIE, "kprobe_cookie");
87
88 ASSERT_EQ(info.perf_event.kprobe.name_len, strlen(KPROBE_FUNC) + 1,
89 "name_len");
90 if (!info.perf_event.kprobe.func_name) {
91 info.perf_event.kprobe.func_name = ptr_to_u64(&buf);
92 info.perf_event.kprobe.name_len = sizeof(buf);
93 goto again;
94 }
95
96 err = strncmp(u64_to_ptr(info.perf_event.kprobe.func_name), KPROBE_FUNC,
97 strlen(KPROBE_FUNC));
98 ASSERT_EQ(err, 0, "cmp_kprobe_func_name");
99 break;
100 case BPF_PERF_EVENT_TRACEPOINT:
101 ASSERT_EQ(info.perf_event.tracepoint.name_len, strlen(TP_NAME) + 1,
102 "name_len");
103 if (!info.perf_event.tracepoint.tp_name) {
104 info.perf_event.tracepoint.tp_name = ptr_to_u64(&buf);
105 info.perf_event.tracepoint.name_len = sizeof(buf);
106 goto again;
107 }
108
109 ASSERT_EQ(info.perf_event.tracepoint.cookie, PERF_EVENT_COOKIE, "tracepoint_cookie");
110
111 err = strncmp(u64_to_ptr(info.perf_event.tracepoint.tp_name), TP_NAME,
112 strlen(TP_NAME));
113 ASSERT_EQ(err, 0, "cmp_tp_name");
114 break;
115 case BPF_PERF_EVENT_UPROBE:
116 case BPF_PERF_EVENT_URETPROBE:
117 ASSERT_EQ(info.perf_event.uprobe.offset, offset, "uprobe_offset");
118 ASSERT_EQ(info.perf_event.uprobe.ref_ctr_offset, ref_ctr_offset, "uprobe_ref_ctr_offset");
119
120 ASSERT_EQ(info.perf_event.uprobe.name_len, strlen(UPROBE_FILE) + 1,
121 "name_len");
122 if (!info.perf_event.uprobe.file_name) {
123 info.perf_event.uprobe.file_name = ptr_to_u64(&buf);
124 info.perf_event.uprobe.name_len = sizeof(buf);
125 goto again;
126 }
127
128 ASSERT_EQ(info.perf_event.uprobe.cookie, PERF_EVENT_COOKIE, "uprobe_cookie");
129
130 err = strncmp(u64_to_ptr(info.perf_event.uprobe.file_name), UPROBE_FILE,
131 strlen(UPROBE_FILE));
132 ASSERT_EQ(err, 0, "cmp_file_name");
133 break;
134 case BPF_PERF_EVENT_EVENT:
135 ASSERT_EQ(info.perf_event.event.type, PERF_TYPE_SOFTWARE, "event_type");
136 ASSERT_EQ(info.perf_event.event.config, PERF_COUNT_SW_PAGE_FAULTS, "event_config");
137 ASSERT_EQ(info.perf_event.event.cookie, PERF_EVENT_COOKIE, "event_cookie");
138 break;
139 default:
140 err = -1;
141 break;
142 }
143 return err;
144 }
145
kprobe_fill_invalid_user_buffer(int fd)146 static void kprobe_fill_invalid_user_buffer(int fd)
147 {
148 struct bpf_link_info info;
149 __u32 len = sizeof(info);
150 int err;
151
152 memset(&info, 0, sizeof(info));
153
154 info.perf_event.kprobe.func_name = 0x1; /* invalid address */
155 err = bpf_link_get_info_by_fd(fd, &info, &len);
156 ASSERT_EQ(err, -EINVAL, "invalid_buff_and_len");
157
158 info.perf_event.kprobe.name_len = 64;
159 err = bpf_link_get_info_by_fd(fd, &info, &len);
160 ASSERT_EQ(err, -EFAULT, "invalid_buff");
161
162 info.perf_event.kprobe.func_name = 0;
163 err = bpf_link_get_info_by_fd(fd, &info, &len);
164 ASSERT_EQ(err, -EINVAL, "invalid_len");
165
166 ASSERT_EQ(info.perf_event.kprobe.addr, 0, "func_addr");
167 ASSERT_EQ(info.perf_event.kprobe.offset, 0, "func_offset");
168 ASSERT_EQ(info.perf_event.type, 0, "type");
169 }
170
test_kprobe_fill_link_info(struct test_fill_link_info * skel,enum bpf_perf_event_type type,bool invalid)171 static void test_kprobe_fill_link_info(struct test_fill_link_info *skel,
172 enum bpf_perf_event_type type,
173 bool invalid)
174 {
175 DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts,
176 .attach_mode = PROBE_ATTACH_MODE_LINK,
177 .retprobe = type == BPF_PERF_EVENT_KRETPROBE,
178 .bpf_cookie = PERF_EVENT_COOKIE,
179 );
180 ssize_t entry_offset = 0;
181 struct bpf_link *link;
182 int link_fd, err;
183
184 link = bpf_program__attach_kprobe_opts(skel->progs.kprobe_run, KPROBE_FUNC, &opts);
185 if (!ASSERT_OK_PTR(link, "attach_kprobe"))
186 return;
187
188 link_fd = bpf_link__fd(link);
189 if (!invalid) {
190 /* See also arch_adjust_kprobe_addr(). */
191 if (skel->kconfig->CONFIG_X86_KERNEL_IBT)
192 entry_offset = 4;
193 if (skel->kconfig->CONFIG_PPC64 &&
194 skel->kconfig->CONFIG_KPROBES_ON_FTRACE &&
195 !skel->kconfig->CONFIG_PPC_FTRACE_OUT_OF_LINE)
196 entry_offset = 4;
197 err = verify_perf_link_info(link_fd, type, kprobe_addr, 0, entry_offset);
198 ASSERT_OK(err, "verify_perf_link_info");
199 } else {
200 kprobe_fill_invalid_user_buffer(link_fd);
201 }
202 bpf_link__destroy(link);
203 }
204
test_tp_fill_link_info(struct test_fill_link_info * skel)205 static void test_tp_fill_link_info(struct test_fill_link_info *skel)
206 {
207 DECLARE_LIBBPF_OPTS(bpf_tracepoint_opts, opts,
208 .bpf_cookie = PERF_EVENT_COOKIE,
209 );
210 struct bpf_link *link;
211 int link_fd, err;
212
213 link = bpf_program__attach_tracepoint_opts(skel->progs.tp_run, TP_CAT, TP_NAME, &opts);
214 if (!ASSERT_OK_PTR(link, "attach_tp"))
215 return;
216
217 link_fd = bpf_link__fd(link);
218 err = verify_perf_link_info(link_fd, BPF_PERF_EVENT_TRACEPOINT, 0, 0, 0);
219 ASSERT_OK(err, "verify_perf_link_info");
220 bpf_link__destroy(link);
221 }
222
test_event_fill_link_info(struct test_fill_link_info * skel)223 static void test_event_fill_link_info(struct test_fill_link_info *skel)
224 {
225 DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, opts,
226 .bpf_cookie = PERF_EVENT_COOKIE,
227 );
228 struct bpf_link *link;
229 int link_fd, err, pfd;
230 struct perf_event_attr attr = {
231 .type = PERF_TYPE_SOFTWARE,
232 .config = PERF_COUNT_SW_PAGE_FAULTS,
233 .freq = 1,
234 .sample_freq = 1,
235 .size = sizeof(struct perf_event_attr),
236 };
237
238 pfd = syscall(__NR_perf_event_open, &attr, -1 /* pid */, 0 /* cpu 0 */,
239 -1 /* group id */, 0 /* flags */);
240 if (!ASSERT_GE(pfd, 0, "perf_event_open"))
241 return;
242
243 link = bpf_program__attach_perf_event_opts(skel->progs.event_run, pfd, &opts);
244 if (!ASSERT_OK_PTR(link, "attach_event"))
245 goto error;
246
247 link_fd = bpf_link__fd(link);
248 err = verify_perf_link_info(link_fd, BPF_PERF_EVENT_EVENT, 0, 0, 0);
249 ASSERT_OK(err, "verify_perf_link_info");
250 bpf_link__destroy(link);
251
252 error:
253 close(pfd);
254 }
255
test_uprobe_fill_link_info(struct test_fill_link_info * skel,enum bpf_perf_event_type type)256 static void test_uprobe_fill_link_info(struct test_fill_link_info *skel,
257 enum bpf_perf_event_type type)
258 {
259 DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, opts,
260 .retprobe = type == BPF_PERF_EVENT_URETPROBE,
261 .bpf_cookie = PERF_EVENT_COOKIE,
262 );
263 const char *sema[1] = {
264 "uprobe_link_info_sema_1",
265 };
266 __u64 *ref_ctr_offset;
267 struct bpf_link *link;
268 int link_fd, err;
269
270 err = elf_resolve_syms_offsets("/proc/self/exe", 1, sema,
271 (unsigned long **) &ref_ctr_offset, STT_OBJECT);
272 if (!ASSERT_OK(err, "elf_resolve_syms_offsets_object"))
273 return;
274
275 opts.ref_ctr_offset = *ref_ctr_offset;
276 link = bpf_program__attach_uprobe_opts(skel->progs.uprobe_run,
277 0, /* self pid */
278 UPROBE_FILE, uprobe_offset,
279 &opts);
280 if (!ASSERT_OK_PTR(link, "attach_uprobe"))
281 goto out;
282
283 link_fd = bpf_link__fd(link);
284 err = verify_perf_link_info(link_fd, type, 0, uprobe_offset, *ref_ctr_offset);
285 ASSERT_OK(err, "verify_perf_link_info");
286 bpf_link__destroy(link);
287 out:
288 free(ref_ctr_offset);
289 }
290
verify_kmulti_link_info(int fd,bool retprobe,bool has_cookies)291 static int verify_kmulti_link_info(int fd, bool retprobe, bool has_cookies)
292 {
293 __u64 addrs[KMULTI_CNT], cookies[KMULTI_CNT];
294 struct bpf_link_info info;
295 __u32 len = sizeof(info);
296 int flags, i, err;
297
298 memset(&info, 0, sizeof(info));
299
300 again:
301 err = bpf_link_get_info_by_fd(fd, &info, &len);
302 if (!ASSERT_OK(err, "get_link_info"))
303 return -1;
304
305 if (!ASSERT_EQ(info.type, BPF_LINK_TYPE_KPROBE_MULTI, "kmulti_type"))
306 return -1;
307
308 ASSERT_EQ(info.kprobe_multi.count, KMULTI_CNT, "func_cnt");
309 flags = info.kprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN;
310 if (!retprobe)
311 ASSERT_EQ(flags, 0, "kmulti_flags");
312 else
313 ASSERT_NEQ(flags, 0, "kretmulti_flags");
314
315 if (!info.kprobe_multi.addrs) {
316 info.kprobe_multi.addrs = ptr_to_u64(addrs);
317 info.kprobe_multi.cookies = ptr_to_u64(cookies);
318 goto again;
319 }
320 for (i = 0; i < KMULTI_CNT; i++) {
321 ASSERT_EQ(addrs[i], kmulti_addrs[i], "kmulti_addrs");
322 ASSERT_EQ(cookies[i], has_cookies ? kmulti_cookies[i] : 0,
323 "kmulti_cookies_value");
324 }
325 return 0;
326 }
327
verify_kmulti_invalid_user_buffer(int fd)328 static void verify_kmulti_invalid_user_buffer(int fd)
329 {
330 __u64 addrs[KMULTI_CNT], cookies[KMULTI_CNT];
331 struct bpf_link_info info;
332 __u32 len = sizeof(info);
333 int err, i;
334
335 memset(&info, 0, sizeof(info));
336
337 info.kprobe_multi.count = KMULTI_CNT;
338 err = bpf_link_get_info_by_fd(fd, &info, &len);
339 ASSERT_EQ(err, -EINVAL, "no_addr");
340
341 info.kprobe_multi.addrs = ptr_to_u64(addrs);
342 info.kprobe_multi.count = 0;
343 err = bpf_link_get_info_by_fd(fd, &info, &len);
344 ASSERT_EQ(err, -EINVAL, "no_cnt");
345
346 for (i = 0; i < KMULTI_CNT; i++)
347 addrs[i] = 0;
348 info.kprobe_multi.count = KMULTI_CNT - 1;
349 err = bpf_link_get_info_by_fd(fd, &info, &len);
350 ASSERT_EQ(err, -ENOSPC, "smaller_cnt");
351 for (i = 0; i < KMULTI_CNT - 1; i++)
352 ASSERT_EQ(addrs[i], kmulti_addrs[i], "kmulti_addrs");
353 ASSERT_EQ(addrs[i], 0, "kmulti_addrs");
354
355 for (i = 0; i < KMULTI_CNT; i++)
356 addrs[i] = 0;
357 info.kprobe_multi.count = KMULTI_CNT + 1;
358 err = bpf_link_get_info_by_fd(fd, &info, &len);
359 ASSERT_EQ(err, 0, "bigger_cnt");
360 for (i = 0; i < KMULTI_CNT; i++)
361 ASSERT_EQ(addrs[i], kmulti_addrs[i], "kmulti_addrs");
362
363 info.kprobe_multi.count = KMULTI_CNT;
364 info.kprobe_multi.addrs = 0x1; /* invalid addr */
365 err = bpf_link_get_info_by_fd(fd, &info, &len);
366 ASSERT_EQ(err, -EFAULT, "invalid_buff_addrs");
367
368 info.kprobe_multi.count = KMULTI_CNT;
369 info.kprobe_multi.addrs = ptr_to_u64(addrs);
370 info.kprobe_multi.cookies = 0x1; /* invalid addr */
371 err = bpf_link_get_info_by_fd(fd, &info, &len);
372 ASSERT_EQ(err, -EFAULT, "invalid_buff_cookies");
373
374 /* cookies && !count */
375 info.kprobe_multi.count = 0;
376 info.kprobe_multi.addrs = ptr_to_u64(NULL);
377 info.kprobe_multi.cookies = ptr_to_u64(cookies);
378 err = bpf_link_get_info_by_fd(fd, &info, &len);
379 ASSERT_EQ(err, -EINVAL, "invalid_cookies_count");
380 }
381
symbols_cmp_r(const void * a,const void * b)382 static int symbols_cmp_r(const void *a, const void *b)
383 {
384 const char **str_a = (const char **) a;
385 const char **str_b = (const char **) b;
386
387 return strcmp(*str_a, *str_b);
388 }
389
test_kprobe_multi_fill_link_info(struct test_fill_link_info * skel,bool retprobe,bool cookies,bool invalid)390 static void test_kprobe_multi_fill_link_info(struct test_fill_link_info *skel,
391 bool retprobe, bool cookies,
392 bool invalid)
393 {
394 LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
395 struct bpf_link *link;
396 int link_fd, err;
397
398 opts.syms = kmulti_syms;
399 opts.cookies = cookies ? kmulti_cookies : NULL;
400 opts.cnt = KMULTI_CNT;
401 opts.retprobe = retprobe;
402 link = bpf_program__attach_kprobe_multi_opts(skel->progs.kmulti_run, NULL, &opts);
403 if (!ASSERT_OK_PTR(link, "attach_kprobe_multi"))
404 return;
405
406 link_fd = bpf_link__fd(link);
407 if (!invalid) {
408 err = verify_kmulti_link_info(link_fd, retprobe, cookies);
409 ASSERT_OK(err, "verify_kmulti_link_info");
410 } else {
411 verify_kmulti_invalid_user_buffer(link_fd);
412 }
413 bpf_link__destroy(link);
414 }
415
tmulti_target_cmp(const void * a,const void * b)416 static int tmulti_target_cmp(const void *a, const void *b)
417 {
418 const struct tmulti_target *ta = a;
419 const struct tmulti_target *tb = b;
420
421 return (ta->id > tb->id) - (ta->id < tb->id);
422 }
423
setup_tmulti_targets(const struct bpf_program * prog,struct tmulti_target * targets,__u32 * btf_obj_id)424 static int setup_tmulti_targets(const struct bpf_program *prog,
425 struct tmulti_target *targets,
426 __u32 *btf_obj_id)
427 {
428 struct bpf_prog_info prog_info;
429 __u32 len = sizeof(prog_info);
430 struct btf *btf;
431 int err, i;
432 __s32 id;
433
434 btf = btf__load_vmlinux_btf();
435 if (!ASSERT_OK_PTR(btf, "btf__load_vmlinux_btf"))
436 return -1;
437
438 for (i = 0; i < TRACING_MULTI_CNT; i++) {
439 id = btf__find_by_name_kind(btf, tmulti_syms[i], BTF_KIND_FUNC);
440 if (!ASSERT_GT(id, 0, "btf__find_by_name_kind"))
441 goto error;
442
443 targets[i].name = tmulti_syms[i];
444 targets[i].addr = ksym_get_addr(tmulti_syms[i]);
445 targets[i].cookie = tmulti_cookies[i];
446 targets[i].id = id;
447 }
448
449 memset(&prog_info, 0, len);
450 err = bpf_prog_get_info_by_fd(bpf_program__fd(prog), &prog_info, &len);
451 if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd"))
452 goto error;
453 if (!ASSERT_GT(prog_info.attach_btf_obj_id, 0, "attach_btf_obj_id"))
454 goto error;
455 *btf_obj_id = prog_info.attach_btf_obj_id;
456
457 /*
458 * The kernel tracing multi attach sorts ids. We sort as well,
459 * so we can easily compare ids and cookies later.
460 */
461 qsort(targets, TRACING_MULTI_CNT, sizeof(targets[0]), tmulti_target_cmp);
462 btf__free(btf);
463 return 0;
464
465 error:
466 btf__free(btf);
467 return -1;
468 }
469
verify_tracing_multi_link_info(int fd,const struct bpf_program * prog,const struct tmulti_target * targets,__u32 btf_obj_id,bool has_cookies)470 static int verify_tracing_multi_link_info(int fd, const struct bpf_program *prog,
471 const struct tmulti_target *targets,
472 __u32 btf_obj_id, bool has_cookies)
473 {
474 enum bpf_attach_type attach_type = bpf_program__expected_attach_type(prog);
475 __u64 addrs[TRACING_MULTI_CNT], cookies[TRACING_MULTI_CNT];
476 __u32 ids[TRACING_MULTI_CNT];
477 struct bpf_link_info info;
478 __u32 len = sizeof(info);
479 int err, i;
480
481 memset(&info, 0, sizeof(info));
482 err = bpf_link_get_info_by_fd(fd, &info, &len);
483 if (!ASSERT_OK(err, "bpf_link_get_info_by_fd"))
484 return -1;
485
486 if (!ASSERT_EQ(info.type, BPF_LINK_TYPE_TRACING_MULTI, "info.type"))
487 return -1;
488
489 ASSERT_EQ(info.tracing_multi.attach_type, attach_type, "info.tracing_multi.attach_type");
490 ASSERT_EQ(info.tracing_multi.count, TRACING_MULTI_CNT, "info.tracing_multi.count");
491
492 memset(ids, 0, sizeof(ids));
493 memset(cookies, 0, sizeof(cookies));
494 memset(addrs, 0, sizeof(addrs));
495
496 info.tracing_multi.ids = ptr_to_u64(ids);
497 info.tracing_multi.addrs = ptr_to_u64(addrs);
498 info.tracing_multi.cookies = has_cookies ? ptr_to_u64(cookies) : 0;
499 info.tracing_multi.count = TRACING_MULTI_CNT;
500
501 err = bpf_link_get_info_by_fd(fd, &info, &len);
502 if (!ASSERT_OK(err, "bpf_link_get_info_by_fd"))
503 return -1;
504
505 if (!ASSERT_EQ(info.type, BPF_LINK_TYPE_TRACING_MULTI, "info.type"))
506 return -1;
507
508 ASSERT_EQ(info.tracing_multi.attach_type, attach_type, "info.tracing_multi.attach_type");
509 ASSERT_EQ(info.tracing_multi.count, TRACING_MULTI_CNT, "info.tracing_multi.count");
510 ASSERT_EQ(info.tracing_multi.btf_obj_id, btf_obj_id, "tracing_multi.btf_obj_id");
511
512 for (i = 0; i < TRACING_MULTI_CNT; i++) {
513 ASSERT_EQ(ids[i], targets[i].id, "tracing_multi.ids");
514 ASSERT_EQ(cookies[i], has_cookies ? targets[i].cookie : 0, "tracing_multi.cookies");
515
516 if (targets[i].addr) {
517 struct ksym *ksym;
518
519 if (!ASSERT_NEQ(addrs[i], 0, "tracing_multi.addrs"))
520 return -1;
521 ksym = ksym_search(addrs[i]);
522 if (!ASSERT_OK_PTR(ksym, "ksym_search"))
523 return -1;
524 ASSERT_STREQ(ksym->name, targets[i].name, "tracing_multi.addr_name");
525 } else {
526 ASSERT_EQ(addrs[i], 0, "tracing_multi.addrs");
527 }
528 }
529
530 return 0;
531 }
532
verify_tracing_multi_invalid_user_buffer(int fd,const struct tmulti_target * targets)533 static void verify_tracing_multi_invalid_user_buffer(int fd, const struct tmulti_target *targets)
534 {
535 __u32 ids[TRACING_MULTI_CNT] = {};
536 struct bpf_link_info info;
537 __u32 len = sizeof(info);
538 int err, i;
539
540 /* Wrong info setup (ids != NULL and cnt == 0) -> EINVAL */
541 memset(&info, 0, sizeof(info));
542 info.tracing_multi.ids = ptr_to_u64(ids);
543 err = bpf_link_get_info_by_fd(fd, &info, &len);
544 ASSERT_EQ(err, -EINVAL, "tracing_multi.invalid_count");
545
546 /* Smaller than actual count provided -> ENOSPC */
547 memset(ids, 0, sizeof(ids));
548 memset(&info, 0, sizeof(info));
549 info.tracing_multi.ids = ptr_to_u64(ids);
550 info.tracing_multi.count = TRACING_MULTI_CNT - 1;
551 err = bpf_link_get_info_by_fd(fd, &info, &len);
552 ASSERT_EQ(err, -ENOSPC, "tracing_multi.small_count");
553 for (i = 0; i < TRACING_MULTI_CNT - 1; i++)
554 ASSERT_EQ(ids[i], targets[i].id, "tracing_multi.partial_ids");
555 /* check that the last entry is not populated */
556 ASSERT_EQ(ids[i], 0, "tracing_multi.partial_ids");
557
558 /* Bigger than actual count provided -> OK */
559 memset(ids, 0, sizeof(ids));
560 memset(&info, 0, sizeof(info));
561 info.tracing_multi.ids = ptr_to_u64(ids);
562 info.tracing_multi.count = TRACING_MULTI_CNT + 1;
563 err = bpf_link_get_info_by_fd(fd, &info, &len);
564 ASSERT_OK(err, "tracing_multi.big_count");
565 for (i = 0; i < TRACING_MULTI_CNT; i++)
566 ASSERT_EQ(ids[i], targets[i].id, "tracing_multi.ids");
567
568 /* Invalid ids pointer -> EFAULT */
569 memset(&info, 0, sizeof(info));
570 info.tracing_multi.ids = 0x1;
571 info.tracing_multi.count = TRACING_MULTI_CNT;
572 err = bpf_link_get_info_by_fd(fd, &info, &len);
573 ASSERT_EQ(err, -EFAULT, "tracing_multi.bad_btf_ids");
574
575 /* Invalid cookies pointer -> EFAULT */
576 memset(&info, 0, sizeof(info));
577 info.tracing_multi.cookies = 0x1;
578 info.tracing_multi.count = TRACING_MULTI_CNT;
579 err = bpf_link_get_info_by_fd(fd, &info, &len);
580 ASSERT_EQ(err, -EFAULT, "tracing_multi.bad_cookies");
581
582 /* Invalid addrs pointer -> EFAULT */
583 memset(&info, 0, sizeof(info));
584 info.tracing_multi.addrs = 0x1;
585 info.tracing_multi.count = TRACING_MULTI_CNT;
586 err = bpf_link_get_info_by_fd(fd, &info, &len);
587 ASSERT_EQ(err, -EFAULT, "tracing_multi.bad_addrs");
588 }
589
test_tracing_multi_fill_link_info(struct test_fill_link_info * skel,bool has_cookies,bool invalid)590 static void test_tracing_multi_fill_link_info(struct test_fill_link_info *skel,
591 bool has_cookies, bool invalid)
592 {
593 LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
594 struct tmulti_target targets[TRACING_MULTI_CNT];
595 __u32 ids[TRACING_MULTI_CNT], btf_obj_id;
596 __u64 cookies[TRACING_MULTI_CNT];
597 struct bpf_link *link;
598 int link_fd, err, i;
599
600 #ifndef __x86_64__
601 test__skip();
602 return;
603 #endif
604
605 if (setup_tmulti_targets(skel->progs.tmulti_run, targets, &btf_obj_id))
606 return;
607
608 for (i = 0; i < TRACING_MULTI_CNT; i++) {
609 ids[i] = targets[i].id;
610 cookies[i] = targets[i].cookie;
611 }
612
613 opts.ids = ids;
614 opts.cnt = TRACING_MULTI_CNT;
615 if (has_cookies)
616 opts.cookies = cookies;
617
618 link = bpf_program__attach_tracing_multi(skel->progs.tmulti_run, NULL, &opts);
619 if (!ASSERT_OK_PTR(link, "bpf_program__attach_tracing_multi"))
620 return;
621
622 link_fd = bpf_link__fd(link);
623 if (invalid) {
624 verify_tracing_multi_invalid_user_buffer(link_fd, targets);
625 } else {
626 err = verify_tracing_multi_link_info(link_fd, skel->progs.tmulti_run,
627 targets, btf_obj_id, has_cookies);
628 ASSERT_OK(err, "verify_tracing_multi_link_info");
629 }
630
631 bpf_link__destroy(link);
632 }
633
634 #define SEC(name) __attribute__((section(name), used))
635
636 static short uprobe_link_info_sema_1 SEC(".probes");
637 static short uprobe_link_info_sema_2 SEC(".probes");
638 static short uprobe_link_info_sema_3 SEC(".probes");
639
uprobe_link_info_func_1(void)640 noinline void uprobe_link_info_func_1(void)
641 {
642 asm volatile ("");
643 uprobe_link_info_sema_1++;
644 }
645
uprobe_link_info_func_2(void)646 noinline void uprobe_link_info_func_2(void)
647 {
648 asm volatile ("");
649 uprobe_link_info_sema_2++;
650 }
651
uprobe_link_info_func_3(void)652 noinline void uprobe_link_info_func_3(void)
653 {
654 asm volatile ("");
655 uprobe_link_info_sema_3++;
656 }
657
658 static int
verify_umulti_link_info(int fd,bool retprobe,__u64 * offsets,__u64 * cookies,__u64 * ref_ctr_offsets)659 verify_umulti_link_info(int fd, bool retprobe, __u64 *offsets,
660 __u64 *cookies, __u64 *ref_ctr_offsets)
661 {
662 char path[PATH_MAX], path_buf[PATH_MAX];
663 struct bpf_link_info info;
664 __u32 len = sizeof(info);
665 __u64 ref_ctr_offsets_buf[3];
666 __u64 offsets_buf[3];
667 __u64 cookies_buf[3];
668 int i, err, bit;
669 __u32 count = 0;
670
671 memset(path, 0, sizeof(path));
672 err = readlink("/proc/self/exe", path, sizeof(path));
673 if (!ASSERT_NEQ(err, -1, "readlink"))
674 return -1;
675
676 memset(&info, 0, sizeof(info));
677 err = bpf_link_get_info_by_fd(fd, &info, &len);
678 if (!ASSERT_OK(err, "bpf_link_get_info_by_fd"))
679 return -1;
680
681 ASSERT_EQ(info.uprobe_multi.count, 3, "info.uprobe_multi.count");
682 ASSERT_EQ(info.uprobe_multi.path_size, strlen(path) + 1,
683 "info.uprobe_multi.path_size");
684
685 for (bit = 0; bit < 8; bit++) {
686 memset(&info, 0, sizeof(info));
687 info.uprobe_multi.path = ptr_to_u64(path_buf);
688 info.uprobe_multi.path_size = sizeof(path_buf);
689 info.uprobe_multi.count = count;
690
691 if (bit & 0x1)
692 info.uprobe_multi.offsets = ptr_to_u64(offsets_buf);
693 if (bit & 0x2)
694 info.uprobe_multi.cookies = ptr_to_u64(cookies_buf);
695 if (bit & 0x4)
696 info.uprobe_multi.ref_ctr_offsets = ptr_to_u64(ref_ctr_offsets_buf);
697
698 err = bpf_link_get_info_by_fd(fd, &info, &len);
699 if (!ASSERT_OK(err, "bpf_link_get_info_by_fd"))
700 return -1;
701
702 if (!ASSERT_EQ(info.type, BPF_LINK_TYPE_UPROBE_MULTI, "info.type"))
703 return -1;
704
705 ASSERT_EQ(info.uprobe_multi.pid, getpid(), "info.uprobe_multi.pid");
706 ASSERT_EQ(info.uprobe_multi.count, 3, "info.uprobe_multi.count");
707 ASSERT_EQ(info.uprobe_multi.flags & BPF_F_UPROBE_MULTI_RETURN,
708 retprobe, "info.uprobe_multi.flags.retprobe");
709 ASSERT_EQ(info.uprobe_multi.path_size, strlen(path) + 1, "info.uprobe_multi.path_size");
710 ASSERT_STREQ(path_buf, path, "info.uprobe_multi.path");
711
712 for (i = 0; i < info.uprobe_multi.count; i++) {
713 if (info.uprobe_multi.offsets)
714 ASSERT_EQ(offsets_buf[i], offsets[i], "info.uprobe_multi.offsets");
715 if (info.uprobe_multi.cookies)
716 ASSERT_EQ(cookies_buf[i], cookies[i], "info.uprobe_multi.cookies");
717 if (info.uprobe_multi.ref_ctr_offsets) {
718 ASSERT_EQ(ref_ctr_offsets_buf[i], ref_ctr_offsets[i],
719 "info.uprobe_multi.ref_ctr_offsets");
720 }
721 }
722 count = count ?: info.uprobe_multi.count;
723 }
724
725 return 0;
726 }
727
verify_umulti_invalid_user_buffer(int fd)728 static void verify_umulti_invalid_user_buffer(int fd)
729 {
730 struct bpf_link_info info;
731 __u32 len = sizeof(info);
732 __u64 buf[3];
733 int err;
734
735 /* upath_size defined, not path */
736 memset(&info, 0, sizeof(info));
737 info.uprobe_multi.path_size = 3;
738 err = bpf_link_get_info_by_fd(fd, &info, &len);
739 ASSERT_EQ(err, -EINVAL, "failed_upath_size");
740
741 /* path defined, but small */
742 memset(&info, 0, sizeof(info));
743 info.uprobe_multi.path = ptr_to_u64(buf);
744 info.uprobe_multi.path_size = 3;
745 err = bpf_link_get_info_by_fd(fd, &info, &len);
746 ASSERT_LT(err, 0, "failed_upath_small");
747
748 /* path has wrong pointer */
749 memset(&info, 0, sizeof(info));
750 info.uprobe_multi.path_size = PATH_MAX;
751 info.uprobe_multi.path = 123;
752 err = bpf_link_get_info_by_fd(fd, &info, &len);
753 ASSERT_EQ(err, -EFAULT, "failed_bad_path_ptr");
754
755 /* count zero, with offsets */
756 memset(&info, 0, sizeof(info));
757 info.uprobe_multi.offsets = ptr_to_u64(buf);
758 err = bpf_link_get_info_by_fd(fd, &info, &len);
759 ASSERT_EQ(err, -EINVAL, "failed_count");
760
761 /* offsets not big enough */
762 memset(&info, 0, sizeof(info));
763 info.uprobe_multi.offsets = ptr_to_u64(buf);
764 info.uprobe_multi.count = 2;
765 err = bpf_link_get_info_by_fd(fd, &info, &len);
766 ASSERT_EQ(err, -ENOSPC, "failed_small_count");
767
768 /* offsets has wrong pointer */
769 memset(&info, 0, sizeof(info));
770 info.uprobe_multi.offsets = 123;
771 info.uprobe_multi.count = 3;
772 err = bpf_link_get_info_by_fd(fd, &info, &len);
773 ASSERT_EQ(err, -EFAULT, "failed_wrong_offsets");
774 }
775
test_uprobe_multi_fill_link_info(struct test_fill_link_info * skel,bool retprobe,bool invalid)776 static void test_uprobe_multi_fill_link_info(struct test_fill_link_info *skel,
777 bool retprobe, bool invalid)
778 {
779 LIBBPF_OPTS(bpf_uprobe_multi_opts, opts,
780 .retprobe = retprobe,
781 );
782 const char *syms[3] = {
783 "uprobe_link_info_func_1",
784 "uprobe_link_info_func_2",
785 "uprobe_link_info_func_3",
786 };
787 __u64 cookies[3] = {
788 0xdead,
789 0xbeef,
790 0xcafe,
791 };
792 const char *sema[3] = {
793 "uprobe_link_info_sema_1",
794 "uprobe_link_info_sema_2",
795 "uprobe_link_info_sema_3",
796 };
797 __u64 *offsets = NULL, *ref_ctr_offsets;
798 struct bpf_link *link;
799 int link_fd, err;
800
801 err = elf_resolve_syms_offsets("/proc/self/exe", 3, sema,
802 (unsigned long **) &ref_ctr_offsets, STT_OBJECT);
803 if (!ASSERT_OK(err, "elf_resolve_syms_offsets_object"))
804 return;
805
806 err = elf_resolve_syms_offsets("/proc/self/exe", 3, syms,
807 (unsigned long **) &offsets, STT_FUNC);
808 if (!ASSERT_OK(err, "elf_resolve_syms_offsets_func"))
809 goto out;
810
811 opts.syms = syms;
812 opts.cookies = &cookies[0];
813 opts.ref_ctr_offsets = (unsigned long *) &ref_ctr_offsets[0];
814 opts.cnt = ARRAY_SIZE(syms);
815
816 link = bpf_program__attach_uprobe_multi(skel->progs.umulti_run, 0,
817 "/proc/self/exe", NULL, &opts);
818 if (!ASSERT_OK_PTR(link, "bpf_program__attach_uprobe_multi"))
819 goto out;
820
821 link_fd = bpf_link__fd(link);
822 if (invalid)
823 verify_umulti_invalid_user_buffer(link_fd);
824 else
825 verify_umulti_link_info(link_fd, retprobe, offsets, cookies, ref_ctr_offsets);
826
827 bpf_link__destroy(link);
828 out:
829 free(ref_ctr_offsets);
830 free(offsets);
831 }
832
test_fill_link_info(void)833 void test_fill_link_info(void)
834 {
835 struct test_fill_link_info *skel;
836 int i;
837
838 skel = test_fill_link_info__open_and_load();
839 if (!ASSERT_OK_PTR(skel, "skel_open"))
840 return;
841
842 /* load kallsyms to compare the addr */
843 if (!ASSERT_OK(load_kallsyms(), "load_kallsyms"))
844 goto cleanup;
845
846 kprobe_addr = ksym_get_addr(KPROBE_FUNC);
847 if (test__start_subtest("kprobe_link_info"))
848 test_kprobe_fill_link_info(skel, BPF_PERF_EVENT_KPROBE, false);
849 if (test__start_subtest("kretprobe_link_info"))
850 test_kprobe_fill_link_info(skel, BPF_PERF_EVENT_KRETPROBE, false);
851 if (test__start_subtest("kprobe_invalid_ubuff"))
852 test_kprobe_fill_link_info(skel, BPF_PERF_EVENT_KPROBE, true);
853 if (test__start_subtest("tracepoint_link_info"))
854 test_tp_fill_link_info(skel);
855 if (test__start_subtest("event_link_info"))
856 test_event_fill_link_info(skel);
857
858 uprobe_offset = get_uprobe_offset(&uprobe_func);
859 if (test__start_subtest("uprobe_link_info"))
860 test_uprobe_fill_link_info(skel, BPF_PERF_EVENT_UPROBE);
861 if (test__start_subtest("uretprobe_link_info"))
862 test_uprobe_fill_link_info(skel, BPF_PERF_EVENT_URETPROBE);
863
864 qsort(kmulti_syms, KMULTI_CNT, sizeof(kmulti_syms[0]), symbols_cmp_r);
865 for (i = 0; i < KMULTI_CNT; i++)
866 kmulti_addrs[i] = ksym_get_addr(kmulti_syms[i]);
867 if (test__start_subtest("kprobe_multi_link_info")) {
868 test_kprobe_multi_fill_link_info(skel, false, false, false);
869 test_kprobe_multi_fill_link_info(skel, false, true, false);
870 }
871 if (test__start_subtest("kretprobe_multi_link_info")) {
872 test_kprobe_multi_fill_link_info(skel, true, false, false);
873 test_kprobe_multi_fill_link_info(skel, true, true, false);
874 }
875 if (test__start_subtest("kprobe_multi_invalid_ubuff"))
876 test_kprobe_multi_fill_link_info(skel, true, true, true);
877
878 if (test__start_subtest("tracing_multi_link_info")) {
879 test_tracing_multi_fill_link_info(skel, false, false);
880 test_tracing_multi_fill_link_info(skel, true, false);
881 }
882 if (test__start_subtest("tracing_multi_invalid_ubuff"))
883 test_tracing_multi_fill_link_info(skel, true, true);
884
885 if (test__start_subtest("uprobe_multi_link_info"))
886 test_uprobe_multi_fill_link_info(skel, false, false);
887 if (test__start_subtest("uretprobe_multi_link_info"))
888 test_uprobe_multi_fill_link_info(skel, true, false);
889 if (test__start_subtest("uprobe_multi_invalid"))
890 test_uprobe_multi_fill_link_info(skel, false, true);
891
892 cleanup:
893 test_fill_link_info__destroy(skel);
894 }
895