xref: /linux/tools/testing/selftests/bpf/prog_tests/fill_link_info.c (revision 5a8cd539ac19f7a68e68e1d25ef9ca2ff55b8500)
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