Skip to content

Commit b813368

Browse files
laoarKernel Patches Daemon
authored and
Kernel Patches Daemon
committed
selftests/bpf: Add selftest for fill_link_info
Add selftest for the fill_link_info of uprobe, kprobe and tracepoint. The result: #78/1 fill_link_info/kprobe_link_info:OK #78/2 fill_link_info/kretprobe_link_info:OK #78/3 fill_link_info/fill_invalid_user_buff:OK #78/4 fill_link_info/tracepoint_link_info:OK #78/5 fill_link_info/uprobe_link_info:OK #78/6 fill_link_info/uretprobe_link_info:OK #78 fill_link_info:OK Summary: 1/6 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Yafang Shao <[email protected]>
1 parent 7409ee9 commit b813368

File tree

3 files changed

+282
-0
lines changed

3 files changed

+282
-0
lines changed
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (C) 2023 Yafang Shao <[email protected]> */
3+
4+
#include <string.h>
5+
#include <linux/bpf.h>
6+
#include <linux/limits.h>
7+
#include <test_progs.h>
8+
#include "trace_helpers.h"
9+
#include "test_fill_link_info.skel.h"
10+
11+
#define TP_CAT "sched"
12+
#define TP_NAME "sched_switch"
13+
#define KPROBE_FUNC "tcp_rcv_established"
14+
#define UPROBE_FILE "/proc/self/exe"
15+
16+
/* uprobe attach point */
17+
static noinline void uprobe_func(void)
18+
{
19+
asm volatile ("");
20+
}
21+
22+
static int verify_link_info(int fd, enum bpf_perf_event_type type, long addr, ssize_t offset)
23+
{
24+
struct bpf_link_info info;
25+
__u32 len = sizeof(info);
26+
char buf[PATH_MAX];
27+
int err = 0;
28+
29+
memset(&info, 0, sizeof(info));
30+
buf[0] = '\0';
31+
32+
again:
33+
err = bpf_link_get_info_by_fd(fd, &info, &len);
34+
if (!ASSERT_OK(err, "get_link_info"))
35+
return -1;
36+
37+
switch (info.type) {
38+
case BPF_LINK_TYPE_PERF_EVENT:
39+
if (!ASSERT_EQ(info.perf_event.type, type, "perf_type_match"))
40+
return -1;
41+
42+
switch (info.perf_event.type) {
43+
case BPF_PERF_EVENT_KPROBE:
44+
case BPF_PERF_EVENT_KRETPROBE:
45+
ASSERT_EQ(info.perf_event.kprobe.offset, offset, "kprobe_offset");
46+
47+
/* In case kptr setting is not permitted or MAX_SYMS is reached */
48+
if (addr) {
49+
long addrs[2] = {
50+
addr + offset,
51+
addr + 0x4, /* For ENDBDR */
52+
};
53+
54+
ASSERT_IN_ARRAY(info.perf_event.kprobe.addr, addrs, "kprobe_addr");
55+
}
56+
57+
if (!info.perf_event.kprobe.func_name) {
58+
ASSERT_EQ(info.perf_event.kprobe.name_len, 0, "name_len");
59+
info.perf_event.kprobe.func_name = ptr_to_u64(&buf);
60+
info.perf_event.kprobe.name_len = sizeof(buf);
61+
goto again;
62+
}
63+
64+
err = strncmp(u64_to_ptr(info.perf_event.kprobe.func_name), KPROBE_FUNC,
65+
strlen(KPROBE_FUNC));
66+
ASSERT_EQ(err, 0, "cmp_kprobe_func_name");
67+
break;
68+
case BPF_PERF_EVENT_TRACEPOINT:
69+
if (!info.perf_event.tracepoint.tp_name) {
70+
ASSERT_EQ(info.perf_event.tracepoint.name_len, 0, "name_len");
71+
info.perf_event.tracepoint.tp_name = ptr_to_u64(&buf);
72+
info.perf_event.tracepoint.name_len = sizeof(buf);
73+
goto again;
74+
}
75+
76+
err = strncmp(u64_to_ptr(info.perf_event.tracepoint.tp_name), TP_NAME,
77+
strlen(TP_NAME));
78+
ASSERT_EQ(err, 0, "cmp_tp_name");
79+
break;
80+
case BPF_PERF_EVENT_UPROBE:
81+
case BPF_PERF_EVENT_URETPROBE:
82+
ASSERT_EQ(info.perf_event.uprobe.offset, offset, "uprobe_offset");
83+
84+
if (!info.perf_event.uprobe.file_name) {
85+
ASSERT_EQ(info.perf_event.uprobe.name_len, 0, "name_len");
86+
info.perf_event.uprobe.file_name = ptr_to_u64(&buf);
87+
info.perf_event.uprobe.name_len = sizeof(buf);
88+
goto again;
89+
}
90+
91+
err = strncmp(u64_to_ptr(info.perf_event.uprobe.file_name), UPROBE_FILE,
92+
strlen(UPROBE_FILE));
93+
ASSERT_EQ(err, 0, "cmp_file_name");
94+
break;
95+
default:
96+
break;
97+
}
98+
break;
99+
default:
100+
switch (type) {
101+
case BPF_PERF_EVENT_KPROBE:
102+
case BPF_PERF_EVENT_KRETPROBE:
103+
case BPF_PERF_EVENT_TRACEPOINT:
104+
case BPF_PERF_EVENT_UPROBE:
105+
case BPF_PERF_EVENT_URETPROBE:
106+
err = -1;
107+
break;
108+
default:
109+
break;
110+
}
111+
break;
112+
}
113+
return err;
114+
}
115+
116+
static void kprobe_fill_invalid_user_buffer(int fd)
117+
{
118+
struct bpf_link_info info;
119+
__u32 len = sizeof(info);
120+
int err = 0;
121+
122+
memset(&info, 0, sizeof(info));
123+
124+
info.perf_event.kprobe.func_name = 0x1; /* invalid address */
125+
err = bpf_link_get_info_by_fd(fd, &info, &len);
126+
ASSERT_EQ(err, -EINVAL, "invalid_buff_and_len");
127+
128+
info.perf_event.kprobe.name_len = 64;
129+
err = bpf_link_get_info_by_fd(fd, &info, &len);
130+
ASSERT_EQ(err, -EFAULT, "invalid_buff");
131+
132+
info.perf_event.kprobe.func_name = 0;
133+
err = bpf_link_get_info_by_fd(fd, &info, &len);
134+
ASSERT_EQ(err, -EINVAL, "invalid_len");
135+
136+
ASSERT_EQ(info.perf_event.kprobe.addr, 0, "func_addr");
137+
ASSERT_EQ(info.perf_event.kprobe.offset, 0, "func_offset");
138+
ASSERT_EQ(info.perf_event.type, 0, "type");
139+
}
140+
141+
static void test_kprobe_fill_link_info(struct test_fill_link_info *skel,
142+
enum bpf_perf_event_type type,
143+
bool retprobe, bool invalid)
144+
{
145+
DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts,
146+
.attach_mode = PROBE_ATTACH_MODE_LINK,
147+
.retprobe = retprobe,
148+
);
149+
int link_fd, err;
150+
long addr;
151+
152+
skel->links.kprobe_run = bpf_program__attach_kprobe_opts(skel->progs.kprobe_run,
153+
KPROBE_FUNC, &opts);
154+
if (!ASSERT_OK_PTR(skel->links.kprobe_run, "attach_kprobe"))
155+
return;
156+
157+
link_fd = bpf_link__fd(skel->links.kprobe_run);
158+
if (!ASSERT_GE(link_fd, 0, "link_fd"))
159+
return;
160+
161+
addr = ksym_get_addr(KPROBE_FUNC);
162+
if (!invalid) {
163+
err = verify_link_info(link_fd, type, addr, 0);
164+
ASSERT_OK(err, "verify_link_info");
165+
} else {
166+
kprobe_fill_invalid_user_buffer(link_fd);
167+
}
168+
bpf_link__detach(skel->links.kprobe_run);
169+
}
170+
171+
static void test_tp_fill_link_info(struct test_fill_link_info *skel)
172+
{
173+
int link_fd, err;
174+
175+
skel->links.tp_run = bpf_program__attach_tracepoint(skel->progs.tp_run, TP_CAT, TP_NAME);
176+
if (!ASSERT_OK_PTR(skel->links.tp_run, "attach_tp"))
177+
return;
178+
179+
link_fd = bpf_link__fd(skel->links.tp_run);
180+
if (!ASSERT_GE(link_fd, 0, "link_fd"))
181+
return;
182+
183+
err = verify_link_info(link_fd, BPF_PERF_EVENT_TRACEPOINT, 0, 0);
184+
ASSERT_OK(err, "verify_link_info");
185+
bpf_link__detach(skel->links.tp_run);
186+
}
187+
188+
static void test_uprobe_fill_link_info(struct test_fill_link_info *skel,
189+
enum bpf_perf_event_type type, ssize_t offset,
190+
bool retprobe)
191+
{
192+
int link_fd, err;
193+
194+
skel->links.uprobe_run = bpf_program__attach_uprobe(skel->progs.uprobe_run, retprobe,
195+
0, /* self pid */
196+
UPROBE_FILE, offset);
197+
if (!ASSERT_OK_PTR(skel->links.uprobe_run, "attach_uprobe"))
198+
return;
199+
200+
link_fd = bpf_link__fd(skel->links.uprobe_run);
201+
if (!ASSERT_GE(link_fd, 0, "link_fd"))
202+
return;
203+
204+
err = verify_link_info(link_fd, type, 0, offset);
205+
ASSERT_OK(err, "verify_link_info");
206+
bpf_link__detach(skel->links.uprobe_run);
207+
}
208+
209+
void serial_test_fill_link_info(void)
210+
{
211+
struct test_fill_link_info *skel;
212+
ssize_t offset;
213+
214+
skel = test_fill_link_info__open_and_load();
215+
if (!ASSERT_OK_PTR(skel, "skel_open"))
216+
goto cleanup;
217+
218+
/* load kallsyms to compare the addr */
219+
if (!ASSERT_OK(load_kallsyms_refresh(), "load_kallsyms_refresh"))
220+
return;
221+
if (test__start_subtest("kprobe_link_info"))
222+
test_kprobe_fill_link_info(skel, BPF_PERF_EVENT_KPROBE, false, false);
223+
if (test__start_subtest("kretprobe_link_info"))
224+
test_kprobe_fill_link_info(skel, BPF_PERF_EVENT_KRETPROBE, true, false);
225+
if (test__start_subtest("fill_invalid_user_buff"))
226+
test_kprobe_fill_link_info(skel, BPF_PERF_EVENT_KPROBE, false, true);
227+
if (test__start_subtest("tracepoint_link_info"))
228+
test_tp_fill_link_info(skel);
229+
230+
offset = get_uprobe_offset(&uprobe_func);
231+
if (test__start_subtest("uprobe_link_info"))
232+
test_uprobe_fill_link_info(skel, BPF_PERF_EVENT_UPROBE, offset, false);
233+
if (test__start_subtest("uretprobe_link_info"))
234+
test_uprobe_fill_link_info(skel, BPF_PERF_EVENT_URETPROBE, offset, true);
235+
236+
cleanup:
237+
test_fill_link_info__destroy(skel);
238+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (C) 2023 Yafang Shao <[email protected]> */
3+
4+
#include "vmlinux.h"
5+
#include <bpf/bpf_tracing.h>
6+
7+
SEC("kprobe")
8+
int BPF_PROG(kprobe_run)
9+
{
10+
return 0;
11+
}
12+
13+
SEC("uprobe")
14+
int BPF_PROG(uprobe_run)
15+
{
16+
return 0;
17+
}
18+
19+
SEC("tracepoint")
20+
int BPF_PROG(tp_run)
21+
{
22+
return 0;
23+
}
24+
25+
char _license[] SEC("license") = "GPL";

tools/testing/selftests/bpf/test_progs.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,25 @@ int test__join_cgroup(const char *path);
300300
___ok; \
301301
})
302302

303+
#define ASSERT_IN_ARRAY(actual, expected, name) ({ \
304+
static int duration; \
305+
typeof(actual) ___act = (actual); \
306+
typeof((expected)[0]) * ___exp = (expected); \
307+
bool ___ok = false; \
308+
int i; \
309+
\
310+
for (i = 0; i < ARRAY_SIZE(expected); i++) { \
311+
if (___act == ___exp[i]) { \
312+
___ok = true; \
313+
break; \
314+
} \
315+
} \
316+
CHECK(!___ok, (name), \
317+
"unexpected %s: actual %lld not in array\n", \
318+
(name), (long long)(___act)); \
319+
___ok; \
320+
})
321+
303322
#define ASSERT_STREQ(actual, expected, name) ({ \
304323
static int duration = 0; \
305324
const char *___act = actual; \

0 commit comments

Comments
 (0)