diff options
-rw-r--r-- | arch/arm/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes-test.c | 340 |
2 files changed, 342 insertions, 0 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index f7887dc53c1f..c7cbd965af94 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -43,6 +43,8 @@ obj-$(CONFIG_KPROBES) += kprobes-thumb.o | |||
43 | else | 43 | else |
44 | obj-$(CONFIG_KPROBES) += kprobes-arm.o | 44 | obj-$(CONFIG_KPROBES) += kprobes-arm.o |
45 | endif | 45 | endif |
46 | obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o | ||
47 | test-kprobes-objs := kprobes-test.o | ||
46 | obj-$(CONFIG_ATAGS_PROC) += atags.o | 48 | obj-$(CONFIG_ATAGS_PROC) += atags.o |
47 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o | 49 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o |
48 | obj-$(CONFIG_ARM_THUMBEE) += thumbee.o | 50 | obj-$(CONFIG_ARM_THUMBEE) += thumbee.o |
diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c new file mode 100644 index 000000000000..9fff0448c320 --- /dev/null +++ b/arch/arm/kernel/kprobes-test.c | |||
@@ -0,0 +1,340 @@ | |||
1 | /* | ||
2 | * arch/arm/kernel/kprobes-test.c | ||
3 | * | ||
4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. | ||
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 version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/kprobes.h> | ||
14 | |||
15 | #include "kprobes.h" | ||
16 | |||
17 | |||
18 | /* | ||
19 | * Test basic API | ||
20 | */ | ||
21 | |||
22 | static bool test_regs_ok; | ||
23 | static int test_func_instance; | ||
24 | static int pre_handler_called; | ||
25 | static int post_handler_called; | ||
26 | static int jprobe_func_called; | ||
27 | static int kretprobe_handler_called; | ||
28 | |||
29 | #define FUNC_ARG1 0x12345678 | ||
30 | #define FUNC_ARG2 0xabcdef | ||
31 | |||
32 | |||
33 | #ifndef CONFIG_THUMB2_KERNEL | ||
34 | |||
35 | long arm_func(long r0, long r1); | ||
36 | |||
37 | static void __used __naked __arm_kprobes_test_func(void) | ||
38 | { | ||
39 | __asm__ __volatile__ ( | ||
40 | ".arm \n\t" | ||
41 | ".type arm_func, %%function \n\t" | ||
42 | "arm_func: \n\t" | ||
43 | "adds r0, r0, r1 \n\t" | ||
44 | "bx lr \n\t" | ||
45 | ".code "NORMAL_ISA /* Back to Thumb if necessary */ | ||
46 | : : : "r0", "r1", "cc" | ||
47 | ); | ||
48 | } | ||
49 | |||
50 | #else /* CONFIG_THUMB2_KERNEL */ | ||
51 | |||
52 | long thumb16_func(long r0, long r1); | ||
53 | long thumb32even_func(long r0, long r1); | ||
54 | long thumb32odd_func(long r0, long r1); | ||
55 | |||
56 | static void __used __naked __thumb_kprobes_test_funcs(void) | ||
57 | { | ||
58 | __asm__ __volatile__ ( | ||
59 | ".type thumb16_func, %%function \n\t" | ||
60 | "thumb16_func: \n\t" | ||
61 | "adds.n r0, r0, r1 \n\t" | ||
62 | "bx lr \n\t" | ||
63 | |||
64 | ".align \n\t" | ||
65 | ".type thumb32even_func, %%function \n\t" | ||
66 | "thumb32even_func: \n\t" | ||
67 | "adds.w r0, r0, r1 \n\t" | ||
68 | "bx lr \n\t" | ||
69 | |||
70 | ".align \n\t" | ||
71 | "nop.n \n\t" | ||
72 | ".type thumb32odd_func, %%function \n\t" | ||
73 | "thumb32odd_func: \n\t" | ||
74 | "adds.w r0, r0, r1 \n\t" | ||
75 | "bx lr \n\t" | ||
76 | |||
77 | : : : "r0", "r1", "cc" | ||
78 | ); | ||
79 | } | ||
80 | |||
81 | #endif /* CONFIG_THUMB2_KERNEL */ | ||
82 | |||
83 | |||
84 | static int call_test_func(long (*func)(long, long), bool check_test_regs) | ||
85 | { | ||
86 | long ret; | ||
87 | |||
88 | ++test_func_instance; | ||
89 | test_regs_ok = false; | ||
90 | |||
91 | ret = (*func)(FUNC_ARG1, FUNC_ARG2); | ||
92 | if (ret != FUNC_ARG1 + FUNC_ARG2) { | ||
93 | pr_err("FAIL: call_test_func: func returned %lx\n", ret); | ||
94 | return false; | ||
95 | } | ||
96 | |||
97 | if (check_test_regs && !test_regs_ok) { | ||
98 | pr_err("FAIL: test regs not OK\n"); | ||
99 | return false; | ||
100 | } | ||
101 | |||
102 | return true; | ||
103 | } | ||
104 | |||
105 | static int __kprobes pre_handler(struct kprobe *p, struct pt_regs *regs) | ||
106 | { | ||
107 | pre_handler_called = test_func_instance; | ||
108 | if (regs->ARM_r0 == FUNC_ARG1 && regs->ARM_r1 == FUNC_ARG2) | ||
109 | test_regs_ok = true; | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static void __kprobes post_handler(struct kprobe *p, struct pt_regs *regs, | ||
114 | unsigned long flags) | ||
115 | { | ||
116 | post_handler_called = test_func_instance; | ||
117 | if (regs->ARM_r0 != FUNC_ARG1 + FUNC_ARG2 || regs->ARM_r1 != FUNC_ARG2) | ||
118 | test_regs_ok = false; | ||
119 | } | ||
120 | |||
121 | static struct kprobe the_kprobe = { | ||
122 | .addr = 0, | ||
123 | .pre_handler = pre_handler, | ||
124 | .post_handler = post_handler | ||
125 | }; | ||
126 | |||
127 | static int test_kprobe(long (*func)(long, long)) | ||
128 | { | ||
129 | int ret; | ||
130 | |||
131 | the_kprobe.addr = (kprobe_opcode_t *)func; | ||
132 | ret = register_kprobe(&the_kprobe); | ||
133 | if (ret < 0) { | ||
134 | pr_err("FAIL: register_kprobe failed with %d\n", ret); | ||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | ret = call_test_func(func, true); | ||
139 | |||
140 | unregister_kprobe(&the_kprobe); | ||
141 | the_kprobe.flags = 0; /* Clear disable flag to allow reuse */ | ||
142 | |||
143 | if (!ret) | ||
144 | return -EINVAL; | ||
145 | if (pre_handler_called != test_func_instance) { | ||
146 | pr_err("FAIL: kprobe pre_handler not called\n"); | ||
147 | return -EINVAL; | ||
148 | } | ||
149 | if (post_handler_called != test_func_instance) { | ||
150 | pr_err("FAIL: kprobe post_handler not called\n"); | ||
151 | return -EINVAL; | ||
152 | } | ||
153 | if (!call_test_func(func, false)) | ||
154 | return -EINVAL; | ||
155 | if (pre_handler_called == test_func_instance || | ||
156 | post_handler_called == test_func_instance) { | ||
157 | pr_err("FAIL: probe called after unregistering\n"); | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static void __kprobes jprobe_func(long r0, long r1) | ||
165 | { | ||
166 | jprobe_func_called = test_func_instance; | ||
167 | if (r0 == FUNC_ARG1 && r1 == FUNC_ARG2) | ||
168 | test_regs_ok = true; | ||
169 | jprobe_return(); | ||
170 | } | ||
171 | |||
172 | static struct jprobe the_jprobe = { | ||
173 | .entry = jprobe_func, | ||
174 | }; | ||
175 | |||
176 | static int test_jprobe(long (*func)(long, long)) | ||
177 | { | ||
178 | int ret; | ||
179 | |||
180 | the_jprobe.kp.addr = (kprobe_opcode_t *)func; | ||
181 | ret = register_jprobe(&the_jprobe); | ||
182 | if (ret < 0) { | ||
183 | pr_err("FAIL: register_jprobe failed with %d\n", ret); | ||
184 | return ret; | ||
185 | } | ||
186 | |||
187 | ret = call_test_func(func, true); | ||
188 | |||
189 | unregister_jprobe(&the_jprobe); | ||
190 | the_jprobe.kp.flags = 0; /* Clear disable flag to allow reuse */ | ||
191 | |||
192 | if (!ret) | ||
193 | return -EINVAL; | ||
194 | if (jprobe_func_called != test_func_instance) { | ||
195 | pr_err("FAIL: jprobe handler function not called\n"); | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | if (!call_test_func(func, false)) | ||
199 | return -EINVAL; | ||
200 | if (jprobe_func_called == test_func_instance) { | ||
201 | pr_err("FAIL: probe called after unregistering\n"); | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static int __kprobes | ||
209 | kretprobe_handler(struct kretprobe_instance *ri, struct pt_regs *regs) | ||
210 | { | ||
211 | kretprobe_handler_called = test_func_instance; | ||
212 | if (regs_return_value(regs) == FUNC_ARG1 + FUNC_ARG2) | ||
213 | test_regs_ok = true; | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static struct kretprobe the_kretprobe = { | ||
218 | .handler = kretprobe_handler, | ||
219 | }; | ||
220 | |||
221 | static int test_kretprobe(long (*func)(long, long)) | ||
222 | { | ||
223 | int ret; | ||
224 | |||
225 | the_kretprobe.kp.addr = (kprobe_opcode_t *)func; | ||
226 | ret = register_kretprobe(&the_kretprobe); | ||
227 | if (ret < 0) { | ||
228 | pr_err("FAIL: register_kretprobe failed with %d\n", ret); | ||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | ret = call_test_func(func, true); | ||
233 | |||
234 | unregister_kretprobe(&the_kretprobe); | ||
235 | the_kretprobe.kp.flags = 0; /* Clear disable flag to allow reuse */ | ||
236 | |||
237 | if (!ret) | ||
238 | return -EINVAL; | ||
239 | if (kretprobe_handler_called != test_func_instance) { | ||
240 | pr_err("FAIL: kretprobe handler not called\n"); | ||
241 | return -EINVAL; | ||
242 | } | ||
243 | if (!call_test_func(func, false)) | ||
244 | return -EINVAL; | ||
245 | if (jprobe_func_called == test_func_instance) { | ||
246 | pr_err("FAIL: kretprobe called after unregistering\n"); | ||
247 | return -EINVAL; | ||
248 | } | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int run_api_tests(long (*func)(long, long)) | ||
254 | { | ||
255 | int ret; | ||
256 | |||
257 | pr_info(" kprobe\n"); | ||
258 | ret = test_kprobe(func); | ||
259 | if (ret < 0) | ||
260 | return ret; | ||
261 | |||
262 | pr_info(" jprobe\n"); | ||
263 | ret = test_jprobe(func); | ||
264 | if (ret < 0) | ||
265 | return ret; | ||
266 | |||
267 | pr_info(" kretprobe\n"); | ||
268 | ret = test_kretprobe(func); | ||
269 | if (ret < 0) | ||
270 | return ret; | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | |||
276 | /* | ||
277 | * Top level test functions | ||
278 | */ | ||
279 | |||
280 | static int __init run_all_tests(void) | ||
281 | { | ||
282 | int ret = 0; | ||
283 | |||
284 | pr_info("Begining kprobe tests...\n"); | ||
285 | |||
286 | #ifndef CONFIG_THUMB2_KERNEL | ||
287 | |||
288 | pr_info("Probe ARM code\n"); | ||
289 | ret = run_api_tests(arm_func); | ||
290 | if (ret) | ||
291 | goto out; | ||
292 | |||
293 | #else /* CONFIG_THUMB2_KERNEL */ | ||
294 | |||
295 | pr_info("Probe 16-bit Thumb code\n"); | ||
296 | ret = run_api_tests(thumb16_func); | ||
297 | if (ret) | ||
298 | goto out; | ||
299 | |||
300 | pr_info("Probe 32-bit Thumb code, even halfword\n"); | ||
301 | ret = run_api_tests(thumb32even_func); | ||
302 | if (ret) | ||
303 | goto out; | ||
304 | |||
305 | pr_info("Probe 32-bit Thumb code, odd halfword\n"); | ||
306 | ret = run_api_tests(thumb32odd_func); | ||
307 | if (ret) | ||
308 | goto out; | ||
309 | |||
310 | #endif | ||
311 | |||
312 | out: | ||
313 | if (ret == 0) | ||
314 | pr_info("Finished kprobe tests OK\n"); | ||
315 | else | ||
316 | pr_err("kprobe tests failed\n"); | ||
317 | |||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | |||
322 | /* | ||
323 | * Module setup | ||
324 | */ | ||
325 | |||
326 | #ifdef MODULE | ||
327 | |||
328 | static void __exit kprobe_test_exit(void) | ||
329 | { | ||
330 | } | ||
331 | |||
332 | module_init(run_all_tests) | ||
333 | module_exit(kprobe_test_exit) | ||
334 | MODULE_LICENSE("GPL"); | ||
335 | |||
336 | #else /* !MODULE */ | ||
337 | |||
338 | late_initcall(run_all_tests); | ||
339 | |||
340 | #endif | ||