Commit | Line | Data |
---|---|---|
8c1c9356 AM |
1 | /* |
2 | * test_kprobes.c - simple sanity test for *probes | |
3 | * | |
4 | * Copyright IBM Corp. 2008 | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it would be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | |
14 | * the GNU General Public License for more details. | |
15 | */ | |
16 | ||
4878b14b FF |
17 | #define pr_fmt(fmt) "Kprobe smoke test: " fmt |
18 | ||
8c1c9356 AM |
19 | #include <linux/kernel.h> |
20 | #include <linux/kprobes.h> | |
21 | #include <linux/random.h> | |
22 | ||
23 | #define div_factor 3 | |
24 | ||
25 | static u32 rand1, preh_val, posth_val, jph_val; | |
26 | static int errors, handler_errors, num_tests; | |
8e114405 | 27 | static u32 (*target)(u32 value); |
12da3b88 | 28 | static u32 (*target2)(u32 value); |
8c1c9356 AM |
29 | |
30 | static noinline u32 kprobe_target(u32 value) | |
31 | { | |
8c1c9356 AM |
32 | return (value / div_factor); |
33 | } | |
34 | ||
35 | static int kp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |
36 | { | |
37 | preh_val = (rand1 / div_factor); | |
38 | return 0; | |
39 | } | |
40 | ||
41 | static void kp_post_handler(struct kprobe *p, struct pt_regs *regs, | |
42 | unsigned long flags) | |
43 | { | |
44 | if (preh_val != (rand1 / div_factor)) { | |
45 | handler_errors++; | |
4878b14b | 46 | pr_err("incorrect value in post_handler\n"); |
8c1c9356 AM |
47 | } |
48 | posth_val = preh_val + div_factor; | |
49 | } | |
50 | ||
51 | static struct kprobe kp = { | |
52 | .symbol_name = "kprobe_target", | |
53 | .pre_handler = kp_pre_handler, | |
54 | .post_handler = kp_post_handler | |
55 | }; | |
56 | ||
57 | static int test_kprobe(void) | |
58 | { | |
59 | int ret; | |
60 | ||
61 | ret = register_kprobe(&kp); | |
62 | if (ret < 0) { | |
4878b14b | 63 | pr_err("register_kprobe returned %d\n", ret); |
8c1c9356 AM |
64 | return ret; |
65 | } | |
66 | ||
8e114405 | 67 | ret = target(rand1); |
8c1c9356 AM |
68 | unregister_kprobe(&kp); |
69 | ||
70 | if (preh_val == 0) { | |
4878b14b | 71 | pr_err("kprobe pre_handler not called\n"); |
8c1c9356 AM |
72 | handler_errors++; |
73 | } | |
74 | ||
75 | if (posth_val == 0) { | |
4878b14b | 76 | pr_err("kprobe post_handler not called\n"); |
8c1c9356 AM |
77 | handler_errors++; |
78 | } | |
79 | ||
80 | return 0; | |
81 | } | |
82 | ||
12da3b88 MH |
83 | static noinline u32 kprobe_target2(u32 value) |
84 | { | |
85 | return (value / div_factor) + 1; | |
86 | } | |
87 | ||
88 | static int kp_pre_handler2(struct kprobe *p, struct pt_regs *regs) | |
89 | { | |
90 | preh_val = (rand1 / div_factor) + 1; | |
91 | return 0; | |
92 | } | |
93 | ||
94 | static void kp_post_handler2(struct kprobe *p, struct pt_regs *regs, | |
95 | unsigned long flags) | |
96 | { | |
97 | if (preh_val != (rand1 / div_factor) + 1) { | |
98 | handler_errors++; | |
4878b14b | 99 | pr_err("incorrect value in post_handler2\n"); |
12da3b88 MH |
100 | } |
101 | posth_val = preh_val + div_factor; | |
102 | } | |
103 | ||
104 | static struct kprobe kp2 = { | |
105 | .symbol_name = "kprobe_target2", | |
106 | .pre_handler = kp_pre_handler2, | |
107 | .post_handler = kp_post_handler2 | |
108 | }; | |
109 | ||
110 | static int test_kprobes(void) | |
111 | { | |
112 | int ret; | |
113 | struct kprobe *kps[2] = {&kp, &kp2}; | |
114 | ||
fd02e6f7 MH |
115 | /* addr and flags should be cleard for reusing kprobe. */ |
116 | kp.addr = NULL; | |
117 | kp.flags = 0; | |
12da3b88 MH |
118 | ret = register_kprobes(kps, 2); |
119 | if (ret < 0) { | |
4878b14b | 120 | pr_err("register_kprobes returned %d\n", ret); |
12da3b88 MH |
121 | return ret; |
122 | } | |
123 | ||
124 | preh_val = 0; | |
125 | posth_val = 0; | |
126 | ret = target(rand1); | |
127 | ||
128 | if (preh_val == 0) { | |
4878b14b | 129 | pr_err("kprobe pre_handler not called\n"); |
12da3b88 MH |
130 | handler_errors++; |
131 | } | |
132 | ||
133 | if (posth_val == 0) { | |
4878b14b | 134 | pr_err("kprobe post_handler not called\n"); |
12da3b88 MH |
135 | handler_errors++; |
136 | } | |
137 | ||
138 | preh_val = 0; | |
139 | posth_val = 0; | |
140 | ret = target2(rand1); | |
141 | ||
142 | if (preh_val == 0) { | |
4878b14b | 143 | pr_err("kprobe pre_handler2 not called\n"); |
12da3b88 MH |
144 | handler_errors++; |
145 | } | |
146 | ||
147 | if (posth_val == 0) { | |
4878b14b | 148 | pr_err("kprobe post_handler2 not called\n"); |
12da3b88 MH |
149 | handler_errors++; |
150 | } | |
151 | ||
152 | unregister_kprobes(kps, 2); | |
153 | return 0; | |
154 | ||
155 | } | |
156 | ||
8c1c9356 AM |
157 | static u32 j_kprobe_target(u32 value) |
158 | { | |
159 | if (value != rand1) { | |
160 | handler_errors++; | |
4878b14b | 161 | pr_err("incorrect value in jprobe handler\n"); |
8c1c9356 AM |
162 | } |
163 | ||
164 | jph_val = rand1; | |
165 | jprobe_return(); | |
166 | return 0; | |
167 | } | |
168 | ||
169 | static struct jprobe jp = { | |
170 | .entry = j_kprobe_target, | |
171 | .kp.symbol_name = "kprobe_target" | |
172 | }; | |
173 | ||
174 | static int test_jprobe(void) | |
175 | { | |
176 | int ret; | |
177 | ||
178 | ret = register_jprobe(&jp); | |
179 | if (ret < 0) { | |
4878b14b | 180 | pr_err("register_jprobe returned %d\n", ret); |
8c1c9356 AM |
181 | return ret; |
182 | } | |
183 | ||
8e114405 | 184 | ret = target(rand1); |
8c1c9356 AM |
185 | unregister_jprobe(&jp); |
186 | if (jph_val == 0) { | |
4878b14b | 187 | pr_err("jprobe handler not called\n"); |
8c1c9356 AM |
188 | handler_errors++; |
189 | } | |
190 | ||
191 | return 0; | |
192 | } | |
193 | ||
12da3b88 MH |
194 | static struct jprobe jp2 = { |
195 | .entry = j_kprobe_target, | |
196 | .kp.symbol_name = "kprobe_target2" | |
197 | }; | |
198 | ||
199 | static int test_jprobes(void) | |
200 | { | |
201 | int ret; | |
202 | struct jprobe *jps[2] = {&jp, &jp2}; | |
203 | ||
fd02e6f7 MH |
204 | /* addr and flags should be cleard for reusing kprobe. */ |
205 | jp.kp.addr = NULL; | |
206 | jp.kp.flags = 0; | |
12da3b88 MH |
207 | ret = register_jprobes(jps, 2); |
208 | if (ret < 0) { | |
4878b14b | 209 | pr_err("register_jprobes returned %d\n", ret); |
12da3b88 MH |
210 | return ret; |
211 | } | |
212 | ||
213 | jph_val = 0; | |
214 | ret = target(rand1); | |
215 | if (jph_val == 0) { | |
4878b14b | 216 | pr_err("jprobe handler not called\n"); |
12da3b88 MH |
217 | handler_errors++; |
218 | } | |
219 | ||
220 | jph_val = 0; | |
221 | ret = target2(rand1); | |
222 | if (jph_val == 0) { | |
4878b14b | 223 | pr_err("jprobe handler2 not called\n"); |
12da3b88 MH |
224 | handler_errors++; |
225 | } | |
226 | unregister_jprobes(jps, 2); | |
227 | ||
228 | return 0; | |
229 | } | |
8c1c9356 AM |
230 | #ifdef CONFIG_KRETPROBES |
231 | static u32 krph_val; | |
232 | ||
f47cd9b5 AS |
233 | static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) |
234 | { | |
235 | krph_val = (rand1 / div_factor); | |
236 | return 0; | |
237 | } | |
238 | ||
8c1c9356 AM |
239 | static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) |
240 | { | |
241 | unsigned long ret = regs_return_value(regs); | |
242 | ||
243 | if (ret != (rand1 / div_factor)) { | |
244 | handler_errors++; | |
4878b14b | 245 | pr_err("incorrect value in kretprobe handler\n"); |
8c1c9356 | 246 | } |
f47cd9b5 AS |
247 | if (krph_val == 0) { |
248 | handler_errors++; | |
4878b14b | 249 | pr_err("call to kretprobe entry handler failed\n"); |
f47cd9b5 | 250 | } |
8c1c9356 | 251 | |
f47cd9b5 | 252 | krph_val = rand1; |
8c1c9356 AM |
253 | return 0; |
254 | } | |
255 | ||
256 | static struct kretprobe rp = { | |
257 | .handler = return_handler, | |
f47cd9b5 | 258 | .entry_handler = entry_handler, |
8c1c9356 AM |
259 | .kp.symbol_name = "kprobe_target" |
260 | }; | |
261 | ||
262 | static int test_kretprobe(void) | |
263 | { | |
264 | int ret; | |
265 | ||
266 | ret = register_kretprobe(&rp); | |
267 | if (ret < 0) { | |
4878b14b | 268 | pr_err("register_kretprobe returned %d\n", ret); |
8c1c9356 AM |
269 | return ret; |
270 | } | |
271 | ||
8e114405 | 272 | ret = target(rand1); |
8c1c9356 | 273 | unregister_kretprobe(&rp); |
f47cd9b5 | 274 | if (krph_val != rand1) { |
4878b14b | 275 | pr_err("kretprobe handler not called\n"); |
8c1c9356 AM |
276 | handler_errors++; |
277 | } | |
278 | ||
279 | return 0; | |
280 | } | |
12da3b88 MH |
281 | |
282 | static int return_handler2(struct kretprobe_instance *ri, struct pt_regs *regs) | |
283 | { | |
284 | unsigned long ret = regs_return_value(regs); | |
285 | ||
286 | if (ret != (rand1 / div_factor) + 1) { | |
287 | handler_errors++; | |
4878b14b | 288 | pr_err("incorrect value in kretprobe handler2\n"); |
12da3b88 MH |
289 | } |
290 | if (krph_val == 0) { | |
291 | handler_errors++; | |
4878b14b | 292 | pr_err("call to kretprobe entry handler failed\n"); |
12da3b88 MH |
293 | } |
294 | ||
295 | krph_val = rand1; | |
296 | return 0; | |
297 | } | |
298 | ||
299 | static struct kretprobe rp2 = { | |
300 | .handler = return_handler2, | |
301 | .entry_handler = entry_handler, | |
302 | .kp.symbol_name = "kprobe_target2" | |
303 | }; | |
304 | ||
305 | static int test_kretprobes(void) | |
306 | { | |
307 | int ret; | |
308 | struct kretprobe *rps[2] = {&rp, &rp2}; | |
309 | ||
fd02e6f7 MH |
310 | /* addr and flags should be cleard for reusing kprobe. */ |
311 | rp.kp.addr = NULL; | |
312 | rp.kp.flags = 0; | |
12da3b88 MH |
313 | ret = register_kretprobes(rps, 2); |
314 | if (ret < 0) { | |
4878b14b | 315 | pr_err("register_kretprobe returned %d\n", ret); |
12da3b88 MH |
316 | return ret; |
317 | } | |
318 | ||
319 | krph_val = 0; | |
320 | ret = target(rand1); | |
321 | if (krph_val != rand1) { | |
4878b14b | 322 | pr_err("kretprobe handler not called\n"); |
12da3b88 MH |
323 | handler_errors++; |
324 | } | |
325 | ||
326 | krph_val = 0; | |
327 | ret = target2(rand1); | |
328 | if (krph_val != rand1) { | |
4878b14b | 329 | pr_err("kretprobe handler2 not called\n"); |
12da3b88 MH |
330 | handler_errors++; |
331 | } | |
332 | unregister_kretprobes(rps, 2); | |
333 | return 0; | |
334 | } | |
8c1c9356 AM |
335 | #endif /* CONFIG_KRETPROBES */ |
336 | ||
337 | int init_test_probes(void) | |
338 | { | |
339 | int ret; | |
340 | ||
8e114405 | 341 | target = kprobe_target; |
12da3b88 | 342 | target2 = kprobe_target2; |
8e114405 | 343 | |
8c1c9356 | 344 | do { |
6d65df33 | 345 | rand1 = prandom_u32(); |
8c1c9356 AM |
346 | } while (rand1 <= div_factor); |
347 | ||
4878b14b | 348 | pr_info("started\n"); |
8c1c9356 AM |
349 | num_tests++; |
350 | ret = test_kprobe(); | |
351 | if (ret < 0) | |
352 | errors++; | |
353 | ||
12da3b88 MH |
354 | num_tests++; |
355 | ret = test_kprobes(); | |
356 | if (ret < 0) | |
357 | errors++; | |
358 | ||
8c1c9356 AM |
359 | num_tests++; |
360 | ret = test_jprobe(); | |
361 | if (ret < 0) | |
362 | errors++; | |
363 | ||
12da3b88 MH |
364 | num_tests++; |
365 | ret = test_jprobes(); | |
366 | if (ret < 0) | |
367 | errors++; | |
368 | ||
8c1c9356 AM |
369 | #ifdef CONFIG_KRETPROBES |
370 | num_tests++; | |
371 | ret = test_kretprobe(); | |
372 | if (ret < 0) | |
373 | errors++; | |
12da3b88 MH |
374 | |
375 | num_tests++; | |
376 | ret = test_kretprobes(); | |
377 | if (ret < 0) | |
378 | errors++; | |
8c1c9356 AM |
379 | #endif /* CONFIG_KRETPROBES */ |
380 | ||
381 | if (errors) | |
4878b14b | 382 | pr_err("BUG: %d out of %d tests failed\n", errors, num_tests); |
8c1c9356 | 383 | else if (handler_errors) |
4878b14b | 384 | pr_err("BUG: %d error(s) running handlers\n", handler_errors); |
8c1c9356 | 385 | else |
4878b14b | 386 | pr_info("passed successfully\n"); |
8c1c9356 AM |
387 | |
388 | return 0; | |
389 | } |