xref: /linux/lib/tests/test_fprobe.c (revision d1d36025a617906c1f442fe47af4a43532bff374)
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