1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include "kprobe_multi.skel.h"
4 #include "trace_helpers.h"
5 
6 static void kprobe_multi_test_run(struct kprobe_multi *skel, bool test_return)
7 {
8 	LIBBPF_OPTS(bpf_test_run_opts, topts);
9 	int err, prog_fd;
10 
11 	prog_fd = bpf_program__fd(skel->progs.trigger);
12 	err = bpf_prog_test_run_opts(prog_fd, &topts);
13 	ASSERT_OK(err, "test_run");
14 	ASSERT_EQ(topts.retval, 0, "test_run");
15 
16 	ASSERT_EQ(skel->bss->kprobe_test1_result, 1, "kprobe_test1_result");
17 	ASSERT_EQ(skel->bss->kprobe_test2_result, 1, "kprobe_test2_result");
18 	ASSERT_EQ(skel->bss->kprobe_test3_result, 1, "kprobe_test3_result");
19 	ASSERT_EQ(skel->bss->kprobe_test4_result, 1, "kprobe_test4_result");
20 	ASSERT_EQ(skel->bss->kprobe_test5_result, 1, "kprobe_test5_result");
21 	ASSERT_EQ(skel->bss->kprobe_test6_result, 1, "kprobe_test6_result");
22 	ASSERT_EQ(skel->bss->kprobe_test7_result, 1, "kprobe_test7_result");
23 	ASSERT_EQ(skel->bss->kprobe_test8_result, 1, "kprobe_test8_result");
24 
25 	if (test_return) {
26 		ASSERT_EQ(skel->bss->kretprobe_test1_result, 1, "kretprobe_test1_result");
27 		ASSERT_EQ(skel->bss->kretprobe_test2_result, 1, "kretprobe_test2_result");
28 		ASSERT_EQ(skel->bss->kretprobe_test3_result, 1, "kretprobe_test3_result");
29 		ASSERT_EQ(skel->bss->kretprobe_test4_result, 1, "kretprobe_test4_result");
30 		ASSERT_EQ(skel->bss->kretprobe_test5_result, 1, "kretprobe_test5_result");
31 		ASSERT_EQ(skel->bss->kretprobe_test6_result, 1, "kretprobe_test6_result");
32 		ASSERT_EQ(skel->bss->kretprobe_test7_result, 1, "kretprobe_test7_result");
33 		ASSERT_EQ(skel->bss->kretprobe_test8_result, 1, "kretprobe_test8_result");
34 	}
35 }
36 
37 static void test_skel_api(void)
38 {
39 	struct kprobe_multi *skel = NULL;
40 	int err;
41 
42 	skel = kprobe_multi__open_and_load();
43 	if (!ASSERT_OK_PTR(skel, "kprobe_multi__open_and_load"))
44 		goto cleanup;
45 
46 	skel->bss->pid = getpid();
47 	err = kprobe_multi__attach(skel);
48 	if (!ASSERT_OK(err, "kprobe_multi__attach"))
49 		goto cleanup;
50 
51 	kprobe_multi_test_run(skel, true);
52 
53 cleanup:
54 	kprobe_multi__destroy(skel);
55 }
56 
57 static void test_link_api(struct bpf_link_create_opts *opts)
58 {
59 	int prog_fd, link1_fd = -1, link2_fd = -1;
60 	struct kprobe_multi *skel = NULL;
61 
62 	skel = kprobe_multi__open_and_load();
63 	if (!ASSERT_OK_PTR(skel, "fentry_raw_skel_load"))
64 		goto cleanup;
65 
66 	skel->bss->pid = getpid();
67 	prog_fd = bpf_program__fd(skel->progs.test_kprobe);
68 	link1_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_KPROBE_MULTI, opts);
69 	if (!ASSERT_GE(link1_fd, 0, "link_fd"))
70 		goto cleanup;
71 
72 	opts->kprobe_multi.flags = BPF_F_KPROBE_MULTI_RETURN;
73 	prog_fd = bpf_program__fd(skel->progs.test_kretprobe);
74 	link2_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_KPROBE_MULTI, opts);
75 	if (!ASSERT_GE(link2_fd, 0, "link_fd"))
76 		goto cleanup;
77 
78 	kprobe_multi_test_run(skel, true);
79 
80 cleanup:
81 	if (link1_fd != -1)
82 		close(link1_fd);
83 	if (link2_fd != -1)
84 		close(link2_fd);
85 	kprobe_multi__destroy(skel);
86 }
87 
88 #define GET_ADDR(__sym, __addr) ({					\
89 	__addr = ksym_get_addr(__sym);					\
90 	if (!ASSERT_NEQ(__addr, 0, "kallsyms load failed for " #__sym))	\
91 		return;							\
92 })
93 
94 static void test_link_api_addrs(void)
95 {
96 	LIBBPF_OPTS(bpf_link_create_opts, opts);
97 	unsigned long long addrs[8];
98 
99 	GET_ADDR("bpf_fentry_test1", addrs[0]);
100 	GET_ADDR("bpf_fentry_test2", addrs[1]);
101 	GET_ADDR("bpf_fentry_test3", addrs[2]);
102 	GET_ADDR("bpf_fentry_test4", addrs[3]);
103 	GET_ADDR("bpf_fentry_test5", addrs[4]);
104 	GET_ADDR("bpf_fentry_test6", addrs[5]);
105 	GET_ADDR("bpf_fentry_test7", addrs[6]);
106 	GET_ADDR("bpf_fentry_test8", addrs[7]);
107 
108 	opts.kprobe_multi.addrs = (const unsigned long*) addrs;
109 	opts.kprobe_multi.cnt = ARRAY_SIZE(addrs);
110 	test_link_api(&opts);
111 }
112 
113 static void test_link_api_syms(void)
114 {
115 	LIBBPF_OPTS(bpf_link_create_opts, opts);
116 	const char *syms[8] = {
117 		"bpf_fentry_test1",
118 		"bpf_fentry_test2",
119 		"bpf_fentry_test3",
120 		"bpf_fentry_test4",
121 		"bpf_fentry_test5",
122 		"bpf_fentry_test6",
123 		"bpf_fentry_test7",
124 		"bpf_fentry_test8",
125 	};
126 
127 	opts.kprobe_multi.syms = syms;
128 	opts.kprobe_multi.cnt = ARRAY_SIZE(syms);
129 	test_link_api(&opts);
130 }
131 
132 static void
133 test_attach_api(const char *pattern, struct bpf_kprobe_multi_opts *opts)
134 {
135 	struct bpf_link *link1 = NULL, *link2 = NULL;
136 	struct kprobe_multi *skel = NULL;
137 
138 	skel = kprobe_multi__open_and_load();
139 	if (!ASSERT_OK_PTR(skel, "fentry_raw_skel_load"))
140 		goto cleanup;
141 
142 	skel->bss->pid = getpid();
143 	link1 = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe,
144 						      pattern, opts);
145 	if (!ASSERT_OK_PTR(link1, "bpf_program__attach_kprobe_multi_opts"))
146 		goto cleanup;
147 
148 	if (opts) {
149 		opts->retprobe = true;
150 		link2 = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kretprobe,
151 							      pattern, opts);
152 		if (!ASSERT_OK_PTR(link2, "bpf_program__attach_kprobe_multi_opts"))
153 			goto cleanup;
154 	}
155 
156 	kprobe_multi_test_run(skel, !!opts);
157 
158 cleanup:
159 	bpf_link__destroy(link2);
160 	bpf_link__destroy(link1);
161 	kprobe_multi__destroy(skel);
162 }
163 
164 static void test_attach_api_pattern(void)
165 {
166 	LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
167 
168 	test_attach_api("bpf_fentry_test*", &opts);
169 	test_attach_api("bpf_fentry_test?", NULL);
170 }
171 
172 static void test_attach_api_addrs(void)
173 {
174 	LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
175 	unsigned long long addrs[8];
176 
177 	GET_ADDR("bpf_fentry_test1", addrs[0]);
178 	GET_ADDR("bpf_fentry_test2", addrs[1]);
179 	GET_ADDR("bpf_fentry_test3", addrs[2]);
180 	GET_ADDR("bpf_fentry_test4", addrs[3]);
181 	GET_ADDR("bpf_fentry_test5", addrs[4]);
182 	GET_ADDR("bpf_fentry_test6", addrs[5]);
183 	GET_ADDR("bpf_fentry_test7", addrs[6]);
184 	GET_ADDR("bpf_fentry_test8", addrs[7]);
185 
186 	opts.addrs = (const unsigned long *) addrs;
187 	opts.cnt = ARRAY_SIZE(addrs);
188 	test_attach_api(NULL, &opts);
189 }
190 
191 static void test_attach_api_syms(void)
192 {
193 	LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
194 	const char *syms[8] = {
195 		"bpf_fentry_test1",
196 		"bpf_fentry_test2",
197 		"bpf_fentry_test3",
198 		"bpf_fentry_test4",
199 		"bpf_fentry_test5",
200 		"bpf_fentry_test6",
201 		"bpf_fentry_test7",
202 		"bpf_fentry_test8",
203 	};
204 
205 	opts.syms = syms;
206 	opts.cnt = ARRAY_SIZE(syms);
207 	test_attach_api(NULL, &opts);
208 }
209 
210 static void test_attach_api_fails(void)
211 {
212 	LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
213 	struct kprobe_multi *skel = NULL;
214 	struct bpf_link *link = NULL;
215 	unsigned long long addrs[2];
216 	const char *syms[2] = {
217 		"bpf_fentry_test1",
218 		"bpf_fentry_test2",
219 	};
220 	__u64 cookies[2];
221 
222 	addrs[0] = ksym_get_addr("bpf_fentry_test1");
223 	addrs[1] = ksym_get_addr("bpf_fentry_test2");
224 
225 	if (!ASSERT_FALSE(!addrs[0] || !addrs[1], "ksym_get_addr"))
226 		goto cleanup;
227 
228 	skel = kprobe_multi__open_and_load();
229 	if (!ASSERT_OK_PTR(skel, "fentry_raw_skel_load"))
230 		goto cleanup;
231 
232 	skel->bss->pid = getpid();
233 
234 	/* fail_1 - pattern and opts NULL */
235 	link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe,
236 						     NULL, NULL);
237 	if (!ASSERT_ERR_PTR(link, "fail_1"))
238 		goto cleanup;
239 
240 	if (!ASSERT_EQ(libbpf_get_error(link), -EINVAL, "fail_1_error"))
241 		goto cleanup;
242 
243 	/* fail_2 - both addrs and syms set */
244 	opts.addrs = (const unsigned long *) addrs;
245 	opts.syms = syms;
246 	opts.cnt = ARRAY_SIZE(syms);
247 	opts.cookies = NULL;
248 
249 	link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe,
250 						     NULL, &opts);
251 	if (!ASSERT_ERR_PTR(link, "fail_2"))
252 		goto cleanup;
253 
254 	if (!ASSERT_EQ(libbpf_get_error(link), -EINVAL, "fail_2_error"))
255 		goto cleanup;
256 
257 	/* fail_3 - pattern and addrs set */
258 	opts.addrs = (const unsigned long *) addrs;
259 	opts.syms = NULL;
260 	opts.cnt = ARRAY_SIZE(syms);
261 	opts.cookies = NULL;
262 
263 	link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe,
264 						     "ksys_*", &opts);
265 	if (!ASSERT_ERR_PTR(link, "fail_3"))
266 		goto cleanup;
267 
268 	if (!ASSERT_EQ(libbpf_get_error(link), -EINVAL, "fail_3_error"))
269 		goto cleanup;
270 
271 	/* fail_4 - pattern and cnt set */
272 	opts.addrs = NULL;
273 	opts.syms = NULL;
274 	opts.cnt = ARRAY_SIZE(syms);
275 	opts.cookies = NULL;
276 
277 	link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe,
278 						     "ksys_*", &opts);
279 	if (!ASSERT_ERR_PTR(link, "fail_4"))
280 		goto cleanup;
281 
282 	if (!ASSERT_EQ(libbpf_get_error(link), -EINVAL, "fail_4_error"))
283 		goto cleanup;
284 
285 	/* fail_5 - pattern and cookies */
286 	opts.addrs = NULL;
287 	opts.syms = NULL;
288 	opts.cnt = 0;
289 	opts.cookies = cookies;
290 
291 	link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe,
292 						     "ksys_*", &opts);
293 	if (!ASSERT_ERR_PTR(link, "fail_5"))
294 		goto cleanup;
295 
296 	if (!ASSERT_EQ(libbpf_get_error(link), -EINVAL, "fail_5_error"))
297 		goto cleanup;
298 
299 cleanup:
300 	bpf_link__destroy(link);
301 	kprobe_multi__destroy(skel);
302 }
303 
304 void test_kprobe_multi_test(void)
305 {
306 	if (!ASSERT_OK(load_kallsyms(), "load_kallsyms"))
307 		return;
308 
309 	if (test__start_subtest("skel_api"))
310 		test_skel_api();
311 	if (test__start_subtest("link_api_addrs"))
312 		test_link_api_syms();
313 	if (test__start_subtest("link_api_syms"))
314 		test_link_api_addrs();
315 	if (test__start_subtest("attach_api_pattern"))
316 		test_attach_api_pattern();
317 	if (test__start_subtest("attach_api_addrs"))
318 		test_attach_api_addrs();
319 	if (test__start_subtest("attach_api_syms"))
320 		test_attach_api_syms();
321 	if (test__start_subtest("attach_api_fails"))
322 		test_attach_api_fails();
323 }
324