xref: /linux/lib/tests/test_fprobe.c (revision db6fe4d61ece24193eb4d94a82d967501d53358c)
1*db6fe4d6SKees Cook // SPDX-License-Identifier: GPL-2.0-or-later
2*db6fe4d6SKees Cook /*
3*db6fe4d6SKees Cook  * test_fprobe.c - simple sanity test for fprobe
4*db6fe4d6SKees Cook  */
5*db6fe4d6SKees Cook 
6*db6fe4d6SKees Cook #include <linux/kernel.h>
7*db6fe4d6SKees Cook #include <linux/fprobe.h>
8*db6fe4d6SKees Cook #include <linux/random.h>
9*db6fe4d6SKees Cook #include <kunit/test.h>
10*db6fe4d6SKees Cook 
11*db6fe4d6SKees Cook #define div_factor 3
12*db6fe4d6SKees Cook 
13*db6fe4d6SKees Cook static struct kunit *current_test;
14*db6fe4d6SKees Cook 
15*db6fe4d6SKees Cook static u32 rand1, entry_val, exit_val;
16*db6fe4d6SKees Cook 
17*db6fe4d6SKees Cook /* Use indirect calls to avoid inlining the target functions */
18*db6fe4d6SKees Cook static u32 (*target)(u32 value);
19*db6fe4d6SKees Cook static u32 (*target2)(u32 value);
20*db6fe4d6SKees Cook static unsigned long target_ip;
21*db6fe4d6SKees Cook static unsigned long target2_ip;
22*db6fe4d6SKees Cook static int entry_return_value;
23*db6fe4d6SKees Cook 
24*db6fe4d6SKees Cook static noinline u32 fprobe_selftest_target(u32 value)
25*db6fe4d6SKees Cook {
26*db6fe4d6SKees Cook 	return (value / div_factor);
27*db6fe4d6SKees Cook }
28*db6fe4d6SKees Cook 
29*db6fe4d6SKees Cook static noinline u32 fprobe_selftest_target2(u32 value)
30*db6fe4d6SKees Cook {
31*db6fe4d6SKees Cook 	return (value / div_factor) + 1;
32*db6fe4d6SKees Cook }
33*db6fe4d6SKees Cook 
34*db6fe4d6SKees Cook static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip,
35*db6fe4d6SKees Cook 				    unsigned long ret_ip,
36*db6fe4d6SKees Cook 				    struct ftrace_regs *fregs, void *data)
37*db6fe4d6SKees Cook {
38*db6fe4d6SKees Cook 	KUNIT_EXPECT_FALSE(current_test, preemptible());
39*db6fe4d6SKees Cook 	/* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */
40*db6fe4d6SKees Cook 	if (ip != target_ip)
41*db6fe4d6SKees Cook 		KUNIT_EXPECT_EQ(current_test, ip, target2_ip);
42*db6fe4d6SKees Cook 	entry_val = (rand1 / div_factor);
43*db6fe4d6SKees Cook 	if (fp->entry_data_size) {
44*db6fe4d6SKees Cook 		KUNIT_EXPECT_NOT_NULL(current_test, data);
45*db6fe4d6SKees Cook 		if (data)
46*db6fe4d6SKees Cook 			*(u32 *)data = entry_val;
47*db6fe4d6SKees Cook 	} else
48*db6fe4d6SKees Cook 		KUNIT_EXPECT_NULL(current_test, data);
49*db6fe4d6SKees Cook 
50*db6fe4d6SKees Cook 	return entry_return_value;
51*db6fe4d6SKees Cook }
52*db6fe4d6SKees Cook 
53*db6fe4d6SKees Cook static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip,
54*db6fe4d6SKees Cook 				    unsigned long ret_ip,
55*db6fe4d6SKees Cook 				    struct ftrace_regs *fregs, void *data)
56*db6fe4d6SKees Cook {
57*db6fe4d6SKees Cook 	unsigned long ret = ftrace_regs_get_return_value(fregs);
58*db6fe4d6SKees Cook 
59*db6fe4d6SKees Cook 	KUNIT_EXPECT_FALSE(current_test, preemptible());
60*db6fe4d6SKees Cook 	if (ip != target_ip) {
61*db6fe4d6SKees Cook 		KUNIT_EXPECT_EQ(current_test, ip, target2_ip);
62*db6fe4d6SKees Cook 		KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor) + 1);
63*db6fe4d6SKees Cook 	} else
64*db6fe4d6SKees Cook 		KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor));
65*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(current_test, entry_val, (rand1 / div_factor));
66*db6fe4d6SKees Cook 	exit_val = entry_val + div_factor;
67*db6fe4d6SKees Cook 	if (fp->entry_data_size) {
68*db6fe4d6SKees Cook 		KUNIT_EXPECT_NOT_NULL(current_test, data);
69*db6fe4d6SKees Cook 		if (data)
70*db6fe4d6SKees Cook 			KUNIT_EXPECT_EQ(current_test, *(u32 *)data, entry_val);
71*db6fe4d6SKees Cook 	} else
72*db6fe4d6SKees Cook 		KUNIT_EXPECT_NULL(current_test, data);
73*db6fe4d6SKees Cook }
74*db6fe4d6SKees Cook 
75*db6fe4d6SKees Cook /* Test entry only (no rethook) */
76*db6fe4d6SKees Cook static void test_fprobe_entry(struct kunit *test)
77*db6fe4d6SKees Cook {
78*db6fe4d6SKees Cook 	struct fprobe fp_entry = {
79*db6fe4d6SKees Cook 		.entry_handler = fp_entry_handler,
80*db6fe4d6SKees Cook 	};
81*db6fe4d6SKees Cook 
82*db6fe4d6SKees Cook 	current_test = test;
83*db6fe4d6SKees Cook 
84*db6fe4d6SKees Cook 	/* Before register, unregister should be failed. */
85*db6fe4d6SKees Cook 	KUNIT_EXPECT_NE(test, 0, unregister_fprobe(&fp_entry));
86*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp_entry, "fprobe_selftest_target*", NULL));
87*db6fe4d6SKees Cook 
88*db6fe4d6SKees Cook 	entry_val = 0;
89*db6fe4d6SKees Cook 	exit_val = 0;
90*db6fe4d6SKees Cook 	target(rand1);
91*db6fe4d6SKees Cook 	KUNIT_EXPECT_NE(test, 0, entry_val);
92*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, exit_val);
93*db6fe4d6SKees Cook 
94*db6fe4d6SKees Cook 	entry_val = 0;
95*db6fe4d6SKees Cook 	exit_val = 0;
96*db6fe4d6SKees Cook 	target2(rand1);
97*db6fe4d6SKees Cook 	KUNIT_EXPECT_NE(test, 0, entry_val);
98*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, exit_val);
99*db6fe4d6SKees Cook 
100*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp_entry));
101*db6fe4d6SKees Cook }
102*db6fe4d6SKees Cook 
103*db6fe4d6SKees Cook static void test_fprobe(struct kunit *test)
104*db6fe4d6SKees Cook {
105*db6fe4d6SKees Cook 	struct fprobe fp = {
106*db6fe4d6SKees Cook 		.entry_handler = fp_entry_handler,
107*db6fe4d6SKees Cook 		.exit_handler = fp_exit_handler,
108*db6fe4d6SKees Cook 	};
109*db6fe4d6SKees Cook 
110*db6fe4d6SKees Cook 	current_test = test;
111*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target*", NULL));
112*db6fe4d6SKees Cook 
113*db6fe4d6SKees Cook 	entry_val = 0;
114*db6fe4d6SKees Cook 	exit_val = 0;
115*db6fe4d6SKees Cook 	target(rand1);
116*db6fe4d6SKees Cook 	KUNIT_EXPECT_NE(test, 0, entry_val);
117*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
118*db6fe4d6SKees Cook 
119*db6fe4d6SKees Cook 	entry_val = 0;
120*db6fe4d6SKees Cook 	exit_val = 0;
121*db6fe4d6SKees Cook 	target2(rand1);
122*db6fe4d6SKees Cook 	KUNIT_EXPECT_NE(test, 0, entry_val);
123*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
124*db6fe4d6SKees Cook 
125*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
126*db6fe4d6SKees Cook }
127*db6fe4d6SKees Cook 
128*db6fe4d6SKees Cook static void test_fprobe_syms(struct kunit *test)
129*db6fe4d6SKees Cook {
130*db6fe4d6SKees Cook 	static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_target2"};
131*db6fe4d6SKees Cook 	struct fprobe fp = {
132*db6fe4d6SKees Cook 		.entry_handler = fp_entry_handler,
133*db6fe4d6SKees Cook 		.exit_handler = fp_exit_handler,
134*db6fe4d6SKees Cook 	};
135*db6fe4d6SKees Cook 
136*db6fe4d6SKees Cook 	current_test = test;
137*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2));
138*db6fe4d6SKees Cook 
139*db6fe4d6SKees Cook 	entry_val = 0;
140*db6fe4d6SKees Cook 	exit_val = 0;
141*db6fe4d6SKees Cook 	target(rand1);
142*db6fe4d6SKees Cook 	KUNIT_EXPECT_NE(test, 0, entry_val);
143*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
144*db6fe4d6SKees Cook 
145*db6fe4d6SKees Cook 	entry_val = 0;
146*db6fe4d6SKees Cook 	exit_val = 0;
147*db6fe4d6SKees Cook 	target2(rand1);
148*db6fe4d6SKees Cook 	KUNIT_EXPECT_NE(test, 0, entry_val);
149*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
150*db6fe4d6SKees Cook 
151*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
152*db6fe4d6SKees Cook }
153*db6fe4d6SKees Cook 
154*db6fe4d6SKees Cook /* Test private entry_data */
155*db6fe4d6SKees Cook static void test_fprobe_data(struct kunit *test)
156*db6fe4d6SKees Cook {
157*db6fe4d6SKees Cook 	struct fprobe fp = {
158*db6fe4d6SKees Cook 		.entry_handler = fp_entry_handler,
159*db6fe4d6SKees Cook 		.exit_handler = fp_exit_handler,
160*db6fe4d6SKees Cook 		.entry_data_size = sizeof(u32),
161*db6fe4d6SKees Cook 	};
162*db6fe4d6SKees Cook 
163*db6fe4d6SKees Cook 	current_test = test;
164*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target", NULL));
165*db6fe4d6SKees Cook 
166*db6fe4d6SKees Cook 	target(rand1);
167*db6fe4d6SKees Cook 
168*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
169*db6fe4d6SKees Cook }
170*db6fe4d6SKees Cook 
171*db6fe4d6SKees Cook static void test_fprobe_skip(struct kunit *test)
172*db6fe4d6SKees Cook {
173*db6fe4d6SKees Cook 	struct fprobe fp = {
174*db6fe4d6SKees Cook 		.entry_handler = fp_entry_handler,
175*db6fe4d6SKees Cook 		.exit_handler = fp_exit_handler,
176*db6fe4d6SKees Cook 	};
177*db6fe4d6SKees Cook 
178*db6fe4d6SKees Cook 	current_test = test;
179*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target", NULL));
180*db6fe4d6SKees Cook 
181*db6fe4d6SKees Cook 	entry_return_value = 1;
182*db6fe4d6SKees Cook 	entry_val = 0;
183*db6fe4d6SKees Cook 	exit_val = 0;
184*db6fe4d6SKees Cook 	target(rand1);
185*db6fe4d6SKees Cook 	KUNIT_EXPECT_NE(test, 0, entry_val);
186*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, exit_val);
187*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, fp.nmissed);
188*db6fe4d6SKees Cook 	entry_return_value = 0;
189*db6fe4d6SKees Cook 
190*db6fe4d6SKees Cook 	KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
191*db6fe4d6SKees Cook }
192*db6fe4d6SKees Cook 
193*db6fe4d6SKees Cook static unsigned long get_ftrace_location(void *func)
194*db6fe4d6SKees Cook {
195*db6fe4d6SKees Cook 	unsigned long size, addr = (unsigned long)func;
196*db6fe4d6SKees Cook 
197*db6fe4d6SKees Cook 	if (!kallsyms_lookup_size_offset(addr, &size, NULL) || !size)
198*db6fe4d6SKees Cook 		return 0;
199*db6fe4d6SKees Cook 
200*db6fe4d6SKees Cook 	return ftrace_location_range(addr, addr + size - 1);
201*db6fe4d6SKees Cook }
202*db6fe4d6SKees Cook 
203*db6fe4d6SKees Cook static int fprobe_test_init(struct kunit *test)
204*db6fe4d6SKees Cook {
205*db6fe4d6SKees Cook 	rand1 = get_random_u32_above(div_factor);
206*db6fe4d6SKees Cook 	target = fprobe_selftest_target;
207*db6fe4d6SKees Cook 	target2 = fprobe_selftest_target2;
208*db6fe4d6SKees Cook 	target_ip = get_ftrace_location(target);
209*db6fe4d6SKees Cook 	target2_ip = get_ftrace_location(target2);
210*db6fe4d6SKees Cook 
211*db6fe4d6SKees Cook 	return 0;
212*db6fe4d6SKees Cook }
213*db6fe4d6SKees Cook 
214*db6fe4d6SKees Cook static struct kunit_case fprobe_testcases[] = {
215*db6fe4d6SKees Cook 	KUNIT_CASE(test_fprobe_entry),
216*db6fe4d6SKees Cook 	KUNIT_CASE(test_fprobe),
217*db6fe4d6SKees Cook 	KUNIT_CASE(test_fprobe_syms),
218*db6fe4d6SKees Cook 	KUNIT_CASE(test_fprobe_data),
219*db6fe4d6SKees Cook 	KUNIT_CASE(test_fprobe_skip),
220*db6fe4d6SKees Cook 	{}
221*db6fe4d6SKees Cook };
222*db6fe4d6SKees Cook 
223*db6fe4d6SKees Cook static struct kunit_suite fprobe_test_suite = {
224*db6fe4d6SKees Cook 	.name = "fprobe_test",
225*db6fe4d6SKees Cook 	.init = fprobe_test_init,
226*db6fe4d6SKees Cook 	.test_cases = fprobe_testcases,
227*db6fe4d6SKees Cook };
228*db6fe4d6SKees Cook 
229*db6fe4d6SKees Cook kunit_test_suites(&fprobe_test_suite);
230*db6fe4d6SKees Cook 
231