1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * test_fprobe.c - simple sanity test for fprobe
4 */
5
6 #include <linux/kernel.h>
7 #include <linux/fprobe.h>
8 #include <linux/random.h>
9 #include <kunit/test.h>
10
11 #define div_factor 3
12
13 static struct kunit *current_test;
14
15 static u32 rand1, entry_only_val, entry_val, exit_val;
16 static u32 entry_only_count, entry_count, exit_count;
17
18 /* Use indirect calls to avoid inlining the target functions */
19 static u32 (*target)(u32 value);
20 static u32 (*target2)(u32 value);
21 static unsigned long target_ip;
22 static unsigned long target2_ip;
23 static int entry_return_value;
24
fprobe_selftest_target(u32 value)25 static noinline u32 fprobe_selftest_target(u32 value)
26 {
27 return (value / div_factor);
28 }
29
fprobe_selftest_target2(u32 value)30 static noinline u32 fprobe_selftest_target2(u32 value)
31 {
32 return (value / div_factor) + 1;
33 }
34
fp_entry_handler(struct fprobe * fp,unsigned long ip,unsigned long ret_ip,struct ftrace_regs * fregs,void * data)35 static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip,
36 unsigned long ret_ip,
37 struct ftrace_regs *fregs, void *data)
38 {
39 KUNIT_EXPECT_FALSE(current_test, preemptible());
40 /* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */
41 if (ip != target_ip)
42 KUNIT_EXPECT_EQ(current_test, ip, target2_ip);
43 entry_val = (rand1 / div_factor);
44 if (fp->entry_data_size) {
45 KUNIT_EXPECT_NOT_NULL(current_test, data);
46 if (data)
47 *(u32 *)data = entry_val;
48 } else
49 KUNIT_EXPECT_NULL(current_test, data);
50
51 return entry_return_value;
52 }
53
fp_exit_handler(struct fprobe * fp,unsigned long ip,unsigned long ret_ip,struct ftrace_regs * fregs,void * data)54 static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip,
55 unsigned long ret_ip,
56 struct ftrace_regs *fregs, void *data)
57 {
58 unsigned long ret = ftrace_regs_get_return_value(fregs);
59
60 KUNIT_EXPECT_FALSE(current_test, preemptible());
61 if (ip != target_ip) {
62 KUNIT_EXPECT_EQ(current_test, ip, target2_ip);
63 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor) + 1);
64 } else
65 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor));
66 KUNIT_EXPECT_EQ(current_test, entry_val, (rand1 / div_factor));
67 exit_val = entry_val + div_factor;
68 if (fp->entry_data_size) {
69 KUNIT_EXPECT_NOT_NULL(current_test, data);
70 if (data)
71 KUNIT_EXPECT_EQ(current_test, *(u32 *)data, entry_val);
72 } else
73 KUNIT_EXPECT_NULL(current_test, data);
74 }
75
76 /* Test entry only (no rethook) */
test_fprobe_entry(struct kunit * test)77 static void test_fprobe_entry(struct kunit *test)
78 {
79 struct fprobe fp_entry = {
80 .entry_handler = fp_entry_handler,
81 };
82
83 current_test = test;
84
85 /* Before register, unregister should be failed. */
86 KUNIT_EXPECT_NE(test, 0, unregister_fprobe(&fp_entry));
87 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp_entry, "fprobe_selftest_target*", NULL));
88
89 entry_val = 0;
90 exit_val = 0;
91 target(rand1);
92 KUNIT_EXPECT_NE(test, 0, entry_val);
93 KUNIT_EXPECT_EQ(test, 0, exit_val);
94
95 entry_val = 0;
96 exit_val = 0;
97 target2(rand1);
98 KUNIT_EXPECT_NE(test, 0, entry_val);
99 KUNIT_EXPECT_EQ(test, 0, exit_val);
100
101 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp_entry));
102 }
103
test_fprobe(struct kunit * test)104 static void test_fprobe(struct kunit *test)
105 {
106 struct fprobe fp = {
107 .entry_handler = fp_entry_handler,
108 .exit_handler = fp_exit_handler,
109 };
110
111 current_test = test;
112 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target*", NULL));
113
114 entry_val = 0;
115 exit_val = 0;
116 target(rand1);
117 KUNIT_EXPECT_NE(test, 0, entry_val);
118 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
119
120 entry_val = 0;
121 exit_val = 0;
122 target2(rand1);
123 KUNIT_EXPECT_NE(test, 0, entry_val);
124 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
125
126 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
127 }
128
test_fprobe_syms(struct kunit * test)129 static void test_fprobe_syms(struct kunit *test)
130 {
131 static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_target2"};
132 struct fprobe fp = {
133 .entry_handler = fp_entry_handler,
134 .exit_handler = fp_exit_handler,
135 };
136
137 current_test = test;
138 KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2));
139
140 entry_val = 0;
141 exit_val = 0;
142 target(rand1);
143 KUNIT_EXPECT_NE(test, 0, entry_val);
144 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
145
146 entry_val = 0;
147 exit_val = 0;
148 target2(rand1);
149 KUNIT_EXPECT_NE(test, 0, entry_val);
150 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
151
152 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
153 }
154
155 /* Test private entry_data */
test_fprobe_data(struct kunit * test)156 static void test_fprobe_data(struct kunit *test)
157 {
158 struct fprobe fp = {
159 .entry_handler = fp_entry_handler,
160 .exit_handler = fp_exit_handler,
161 .entry_data_size = sizeof(u32),
162 };
163
164 current_test = test;
165 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target", NULL));
166
167 target(rand1);
168
169 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
170 }
171
test_fprobe_skip(struct kunit * test)172 static void test_fprobe_skip(struct kunit *test)
173 {
174 struct fprobe fp = {
175 .entry_handler = fp_entry_handler,
176 .exit_handler = fp_exit_handler,
177 };
178
179 current_test = test;
180 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target", NULL));
181
182 entry_return_value = 1;
183 entry_val = 0;
184 exit_val = 0;
185 target(rand1);
186 KUNIT_EXPECT_NE(test, 0, entry_val);
187 KUNIT_EXPECT_EQ(test, 0, exit_val);
188 KUNIT_EXPECT_EQ(test, 0, fp.nmissed);
189 entry_return_value = 0;
190
191 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
192 }
193
194 /* Handler for fprobe entry only case */
entry_only_handler(struct fprobe * fp,unsigned long ip,unsigned long ret_ip,struct ftrace_regs * fregs,void * data)195 static notrace int entry_only_handler(struct fprobe *fp, unsigned long ip,
196 unsigned long ret_ip,
197 struct ftrace_regs *fregs, void *data)
198 {
199 KUNIT_EXPECT_FALSE(current_test, preemptible());
200 KUNIT_EXPECT_EQ(current_test, ip, target_ip);
201
202 entry_only_count++;
203 entry_only_val = (rand1 / div_factor);
204
205 return 0;
206 }
207
fprobe_entry_multi_handler(struct fprobe * fp,unsigned long ip,unsigned long ret_ip,struct ftrace_regs * fregs,void * data)208 static notrace int fprobe_entry_multi_handler(struct fprobe *fp, unsigned long ip,
209 unsigned long ret_ip,
210 struct ftrace_regs *fregs,
211 void *data)
212 {
213 KUNIT_EXPECT_FALSE(current_test, preemptible());
214 KUNIT_EXPECT_EQ(current_test, ip, target_ip);
215
216 entry_count++;
217 entry_val = (rand1 / div_factor);
218
219 return 0;
220 }
221
fprobe_exit_multi_handler(struct fprobe * fp,unsigned long ip,unsigned long ret_ip,struct ftrace_regs * fregs,void * data)222 static notrace void fprobe_exit_multi_handler(struct fprobe *fp, unsigned long ip,
223 unsigned long ret_ip,
224 struct ftrace_regs *fregs,
225 void *data)
226 {
227 unsigned long ret = ftrace_regs_get_return_value(fregs);
228
229 KUNIT_EXPECT_FALSE(current_test, preemptible());
230 KUNIT_EXPECT_EQ(current_test, ip, target_ip);
231 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor));
232
233 exit_count++;
234 exit_val = ret;
235 }
236
check_fprobe_multi(struct kunit * test)237 static void check_fprobe_multi(struct kunit *test)
238 {
239 entry_only_count = entry_count = exit_count = 0;
240 entry_only_val = entry_val = exit_val = 0;
241
242 target(rand1);
243
244 /* Verify all handlers were called */
245 KUNIT_EXPECT_EQ(test, 1, entry_only_count);
246 KUNIT_EXPECT_EQ(test, 1, entry_count);
247 KUNIT_EXPECT_EQ(test, 1, exit_count);
248
249 /* Verify values are correct */
250 KUNIT_EXPECT_EQ(test, (rand1 / div_factor), entry_only_val);
251 KUNIT_EXPECT_EQ(test, (rand1 / div_factor), entry_val);
252 KUNIT_EXPECT_EQ(test, (rand1 / div_factor), exit_val);
253 }
254
255 /* Test multiple fprobes hooking the same target function */
test_fprobe_multi(struct kunit * test)256 static void test_fprobe_multi(struct kunit *test)
257 {
258 struct fprobe fp1 = {
259 .entry_handler = fprobe_entry_multi_handler,
260 .exit_handler = fprobe_exit_multi_handler,
261 };
262 struct fprobe fp2 = {
263 .entry_handler = entry_only_handler,
264 };
265
266 current_test = test;
267
268 /* Test Case 1: Register in order 1 -> 2 */
269 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp1, "fprobe_selftest_target", NULL));
270 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp2, "fprobe_selftest_target", NULL));
271
272 check_fprobe_multi(test);
273
274 /* Unregister all */
275 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp1));
276 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp2));
277
278 /* Test Case 2: Register in order 2 -> 1 */
279 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp2, "fprobe_selftest_target", NULL));
280 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp1, "fprobe_selftest_target", NULL));
281
282 check_fprobe_multi(test);
283
284 /* Unregister all */
285 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp1));
286 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp2));
287 }
288
get_ftrace_location(void * func)289 static unsigned long get_ftrace_location(void *func)
290 {
291 unsigned long size, addr = (unsigned long)func;
292
293 if (!kallsyms_lookup_size_offset(addr, &size, NULL) || !size)
294 return 0;
295
296 return ftrace_location_range(addr, addr + size - 1);
297 }
298
fprobe_test_init(struct kunit * test)299 static int fprobe_test_init(struct kunit *test)
300 {
301 rand1 = get_random_u32_above(div_factor);
302 target = fprobe_selftest_target;
303 target2 = fprobe_selftest_target2;
304 target_ip = get_ftrace_location(target);
305 target2_ip = get_ftrace_location(target2);
306
307 return 0;
308 }
309
310 static struct kunit_case fprobe_testcases[] = {
311 KUNIT_CASE(test_fprobe_entry),
312 KUNIT_CASE(test_fprobe),
313 KUNIT_CASE(test_fprobe_syms),
314 KUNIT_CASE(test_fprobe_data),
315 KUNIT_CASE(test_fprobe_skip),
316 KUNIT_CASE(test_fprobe_multi),
317 {}
318 };
319
320 static struct kunit_suite fprobe_test_suite = {
321 .name = "fprobe_test",
322 .init = fprobe_test_init,
323 .test_cases = fprobe_testcases,
324 };
325
326 kunit_test_suites(&fprobe_test_suite);
327
328