diff options
-rw-r--r-- | include/asm-generic/sections.h | 1 | ||||
-rw-r--r-- | include/asm-generic/vmlinux.lds.h | 6 | ||||
-rw-r--r-- | include/linux/kprobes.h | 3 | ||||
-rw-r--r-- | include/linux/linkage.h | 7 | ||||
-rw-r--r-- | kernel/kprobes.c | 72 |
5 files changed, 60 insertions, 29 deletions
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 450eae22c39a..886dbd116899 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h | |||
@@ -12,5 +12,6 @@ extern char _sextratext[] __attribute__((weak)); | |||
12 | extern char _eextratext[] __attribute__((weak)); | 12 | extern char _eextratext[] __attribute__((weak)); |
13 | extern char _end[]; | 13 | extern char _end[]; |
14 | extern char __per_cpu_start[], __per_cpu_end[]; | 14 | extern char __per_cpu_start[], __per_cpu_end[]; |
15 | extern char __kprobes_text_start[], __kprobes_text_end[]; | ||
15 | 16 | ||
16 | #endif /* _ASM_GENERIC_SECTIONS_H_ */ | 17 | #endif /* _ASM_GENERIC_SECTIONS_H_ */ |
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 3fa94288aa93..6f857be2b644 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h | |||
@@ -97,3 +97,9 @@ | |||
97 | VMLINUX_SYMBOL(__lock_text_start) = .; \ | 97 | VMLINUX_SYMBOL(__lock_text_start) = .; \ |
98 | *(.spinlock.text) \ | 98 | *(.spinlock.text) \ |
99 | VMLINUX_SYMBOL(__lock_text_end) = .; | 99 | VMLINUX_SYMBOL(__lock_text_end) = .; |
100 | |||
101 | #define KPROBES_TEXT \ | ||
102 | ALIGN_FUNCTION(); \ | ||
103 | VMLINUX_SYMBOL(__kprobes_text_start) = .; \ | ||
104 | *(.kprobes.text) \ | ||
105 | VMLINUX_SYMBOL(__kprobes_text_end) = .; | ||
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index e050fc2d4c26..e30afdca7917 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h | |||
@@ -42,6 +42,9 @@ | |||
42 | #define KPROBE_REENTER 0x00000004 | 42 | #define KPROBE_REENTER 0x00000004 |
43 | #define KPROBE_HIT_SSDONE 0x00000008 | 43 | #define KPROBE_HIT_SSDONE 0x00000008 |
44 | 44 | ||
45 | /* Attach to insert probes on any functions which should be ignored*/ | ||
46 | #define __kprobes __attribute__((__section__(".kprobes.text"))) | ||
47 | |||
45 | struct kprobe; | 48 | struct kprobe; |
46 | struct pt_regs; | 49 | struct pt_regs; |
47 | struct kretprobe; | 50 | struct kretprobe; |
diff --git a/include/linux/linkage.h b/include/linux/linkage.h index 338f7795d8a0..147eb01e0d4b 100644 --- a/include/linux/linkage.h +++ b/include/linux/linkage.h | |||
@@ -33,6 +33,13 @@ | |||
33 | ALIGN; \ | 33 | ALIGN; \ |
34 | name: | 34 | name: |
35 | 35 | ||
36 | #define KPROBE_ENTRY(name) \ | ||
37 | .section .kprobes.text, "ax"; \ | ||
38 | .globl name; \ | ||
39 | ALIGN; \ | ||
40 | name: | ||
41 | |||
42 | |||
36 | #endif | 43 | #endif |
37 | 44 | ||
38 | #define NORET_TYPE /**/ | 45 | #define NORET_TYPE /**/ |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index b0237122b24e..3b7653f2e7ae 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/init.h> | 37 | #include <linux/init.h> |
38 | #include <linux/module.h> | 38 | #include <linux/module.h> |
39 | #include <linux/moduleloader.h> | 39 | #include <linux/moduleloader.h> |
40 | #include <asm-generic/sections.h> | ||
40 | #include <asm/cacheflush.h> | 41 | #include <asm/cacheflush.h> |
41 | #include <asm/errno.h> | 42 | #include <asm/errno.h> |
42 | #include <asm/kdebug.h> | 43 | #include <asm/kdebug.h> |
@@ -72,7 +73,7 @@ static struct hlist_head kprobe_insn_pages; | |||
72 | * get_insn_slot() - Find a slot on an executable page for an instruction. | 73 | * get_insn_slot() - Find a slot on an executable page for an instruction. |
73 | * We allocate an executable page if there's no room on existing ones. | 74 | * We allocate an executable page if there's no room on existing ones. |
74 | */ | 75 | */ |
75 | kprobe_opcode_t *get_insn_slot(void) | 76 | kprobe_opcode_t __kprobes *get_insn_slot(void) |
76 | { | 77 | { |
77 | struct kprobe_insn_page *kip; | 78 | struct kprobe_insn_page *kip; |
78 | struct hlist_node *pos; | 79 | struct hlist_node *pos; |
@@ -117,7 +118,7 @@ kprobe_opcode_t *get_insn_slot(void) | |||
117 | return kip->insns; | 118 | return kip->insns; |
118 | } | 119 | } |
119 | 120 | ||
120 | void free_insn_slot(kprobe_opcode_t *slot) | 121 | void __kprobes free_insn_slot(kprobe_opcode_t *slot) |
121 | { | 122 | { |
122 | struct kprobe_insn_page *kip; | 123 | struct kprobe_insn_page *kip; |
123 | struct hlist_node *pos; | 124 | struct hlist_node *pos; |
@@ -152,20 +153,20 @@ void free_insn_slot(kprobe_opcode_t *slot) | |||
152 | } | 153 | } |
153 | 154 | ||
154 | /* Locks kprobe: irqs must be disabled */ | 155 | /* Locks kprobe: irqs must be disabled */ |
155 | void lock_kprobes(void) | 156 | void __kprobes lock_kprobes(void) |
156 | { | 157 | { |
157 | spin_lock(&kprobe_lock); | 158 | spin_lock(&kprobe_lock); |
158 | kprobe_cpu = smp_processor_id(); | 159 | kprobe_cpu = smp_processor_id(); |
159 | } | 160 | } |
160 | 161 | ||
161 | void unlock_kprobes(void) | 162 | void __kprobes unlock_kprobes(void) |
162 | { | 163 | { |
163 | kprobe_cpu = NR_CPUS; | 164 | kprobe_cpu = NR_CPUS; |
164 | spin_unlock(&kprobe_lock); | 165 | spin_unlock(&kprobe_lock); |
165 | } | 166 | } |
166 | 167 | ||
167 | /* You have to be holding the kprobe_lock */ | 168 | /* You have to be holding the kprobe_lock */ |
168 | struct kprobe *get_kprobe(void *addr) | 169 | struct kprobe __kprobes *get_kprobe(void *addr) |
169 | { | 170 | { |
170 | struct hlist_head *head; | 171 | struct hlist_head *head; |
171 | struct hlist_node *node; | 172 | struct hlist_node *node; |
@@ -183,7 +184,7 @@ struct kprobe *get_kprobe(void *addr) | |||
183 | * Aggregate handlers for multiple kprobes support - these handlers | 184 | * Aggregate handlers for multiple kprobes support - these handlers |
184 | * take care of invoking the individual kprobe handlers on p->list | 185 | * take care of invoking the individual kprobe handlers on p->list |
185 | */ | 186 | */ |
186 | static int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs) | 187 | static int __kprobes aggr_pre_handler(struct kprobe *p, struct pt_regs *regs) |
187 | { | 188 | { |
188 | struct kprobe *kp; | 189 | struct kprobe *kp; |
189 | 190 | ||
@@ -198,8 +199,8 @@ static int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
198 | return 0; | 199 | return 0; |
199 | } | 200 | } |
200 | 201 | ||
201 | static void aggr_post_handler(struct kprobe *p, struct pt_regs *regs, | 202 | static void __kprobes aggr_post_handler(struct kprobe *p, struct pt_regs *regs, |
202 | unsigned long flags) | 203 | unsigned long flags) |
203 | { | 204 | { |
204 | struct kprobe *kp; | 205 | struct kprobe *kp; |
205 | 206 | ||
@@ -213,8 +214,8 @@ static void aggr_post_handler(struct kprobe *p, struct pt_regs *regs, | |||
213 | return; | 214 | return; |
214 | } | 215 | } |
215 | 216 | ||
216 | static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs, | 217 | static int __kprobes aggr_fault_handler(struct kprobe *p, struct pt_regs *regs, |
217 | int trapnr) | 218 | int trapnr) |
218 | { | 219 | { |
219 | /* | 220 | /* |
220 | * if we faulted "during" the execution of a user specified | 221 | * if we faulted "during" the execution of a user specified |
@@ -227,7 +228,7 @@ static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs, | |||
227 | return 0; | 228 | return 0; |
228 | } | 229 | } |
229 | 230 | ||
230 | static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs) | 231 | static int __kprobes aggr_break_handler(struct kprobe *p, struct pt_regs *regs) |
231 | { | 232 | { |
232 | struct kprobe *kp = curr_kprobe; | 233 | struct kprobe *kp = curr_kprobe; |
233 | if (curr_kprobe && kp->break_handler) { | 234 | if (curr_kprobe && kp->break_handler) { |
@@ -240,7 +241,7 @@ static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs) | |||
240 | return 0; | 241 | return 0; |
241 | } | 242 | } |
242 | 243 | ||
243 | struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp) | 244 | struct kretprobe_instance __kprobes *get_free_rp_inst(struct kretprobe *rp) |
244 | { | 245 | { |
245 | struct hlist_node *node; | 246 | struct hlist_node *node; |
246 | struct kretprobe_instance *ri; | 247 | struct kretprobe_instance *ri; |
@@ -249,7 +250,8 @@ struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp) | |||
249 | return NULL; | 250 | return NULL; |
250 | } | 251 | } |
251 | 252 | ||
252 | static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp) | 253 | static struct kretprobe_instance __kprobes *get_used_rp_inst(struct kretprobe |
254 | *rp) | ||
253 | { | 255 | { |
254 | struct hlist_node *node; | 256 | struct hlist_node *node; |
255 | struct kretprobe_instance *ri; | 257 | struct kretprobe_instance *ri; |
@@ -258,7 +260,7 @@ static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp) | |||
258 | return NULL; | 260 | return NULL; |
259 | } | 261 | } |
260 | 262 | ||
261 | void add_rp_inst(struct kretprobe_instance *ri) | 263 | void __kprobes add_rp_inst(struct kretprobe_instance *ri) |
262 | { | 264 | { |
263 | /* | 265 | /* |
264 | * Remove rp inst off the free list - | 266 | * Remove rp inst off the free list - |
@@ -276,7 +278,7 @@ void add_rp_inst(struct kretprobe_instance *ri) | |||
276 | hlist_add_head(&ri->uflist, &ri->rp->used_instances); | 278 | hlist_add_head(&ri->uflist, &ri->rp->used_instances); |
277 | } | 279 | } |
278 | 280 | ||
279 | void recycle_rp_inst(struct kretprobe_instance *ri) | 281 | void __kprobes recycle_rp_inst(struct kretprobe_instance *ri) |
280 | { | 282 | { |
281 | /* remove rp inst off the rprobe_inst_table */ | 283 | /* remove rp inst off the rprobe_inst_table */ |
282 | hlist_del(&ri->hlist); | 284 | hlist_del(&ri->hlist); |
@@ -291,7 +293,7 @@ void recycle_rp_inst(struct kretprobe_instance *ri) | |||
291 | kfree(ri); | 293 | kfree(ri); |
292 | } | 294 | } |
293 | 295 | ||
294 | struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk) | 296 | struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk) |
295 | { | 297 | { |
296 | return &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)]; | 298 | return &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)]; |
297 | } | 299 | } |
@@ -302,7 +304,7 @@ struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk) | |||
302 | * instances associated with this task. These left over instances represent | 304 | * instances associated with this task. These left over instances represent |
303 | * probed functions that have been called but will never return. | 305 | * probed functions that have been called but will never return. |
304 | */ | 306 | */ |
305 | void kprobe_flush_task(struct task_struct *tk) | 307 | void __kprobes kprobe_flush_task(struct task_struct *tk) |
306 | { | 308 | { |
307 | struct kretprobe_instance *ri; | 309 | struct kretprobe_instance *ri; |
308 | struct hlist_head *head; | 310 | struct hlist_head *head; |
@@ -322,7 +324,8 @@ void kprobe_flush_task(struct task_struct *tk) | |||
322 | * This kprobe pre_handler is registered with every kretprobe. When probe | 324 | * This kprobe pre_handler is registered with every kretprobe. When probe |
323 | * hits it will set up the return probe. | 325 | * hits it will set up the return probe. |
324 | */ | 326 | */ |
325 | static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs) | 327 | static int __kprobes pre_handler_kretprobe(struct kprobe *p, |
328 | struct pt_regs *regs) | ||
326 | { | 329 | { |
327 | struct kretprobe *rp = container_of(p, struct kretprobe, kp); | 330 | struct kretprobe *rp = container_of(p, struct kretprobe, kp); |
328 | 331 | ||
@@ -353,7 +356,7 @@ static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p) | |||
353 | * Add the new probe to old_p->list. Fail if this is the | 356 | * Add the new probe to old_p->list. Fail if this is the |
354 | * second jprobe at the address - two jprobes can't coexist | 357 | * second jprobe at the address - two jprobes can't coexist |
355 | */ | 358 | */ |
356 | static int add_new_kprobe(struct kprobe *old_p, struct kprobe *p) | 359 | static int __kprobes add_new_kprobe(struct kprobe *old_p, struct kprobe *p) |
357 | { | 360 | { |
358 | struct kprobe *kp; | 361 | struct kprobe *kp; |
359 | 362 | ||
@@ -395,7 +398,8 @@ static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p) | |||
395 | * the intricacies | 398 | * the intricacies |
396 | * TODO: Move kcalloc outside the spinlock | 399 | * TODO: Move kcalloc outside the spinlock |
397 | */ | 400 | */ |
398 | static int register_aggr_kprobe(struct kprobe *old_p, struct kprobe *p) | 401 | static int __kprobes register_aggr_kprobe(struct kprobe *old_p, |
402 | struct kprobe *p) | ||
399 | { | 403 | { |
400 | int ret = 0; | 404 | int ret = 0; |
401 | struct kprobe *ap; | 405 | struct kprobe *ap; |
@@ -434,15 +438,25 @@ static inline void cleanup_aggr_kprobe(struct kprobe *old_p, | |||
434 | spin_unlock_irqrestore(&kprobe_lock, flags); | 438 | spin_unlock_irqrestore(&kprobe_lock, flags); |
435 | } | 439 | } |
436 | 440 | ||
437 | int register_kprobe(struct kprobe *p) | 441 | static int __kprobes in_kprobes_functions(unsigned long addr) |
442 | { | ||
443 | if (addr >= (unsigned long)__kprobes_text_start | ||
444 | && addr < (unsigned long)__kprobes_text_end) | ||
445 | return -EINVAL; | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | int __kprobes register_kprobe(struct kprobe *p) | ||
438 | { | 450 | { |
439 | int ret = 0; | 451 | int ret = 0; |
440 | unsigned long flags = 0; | 452 | unsigned long flags = 0; |
441 | struct kprobe *old_p; | 453 | struct kprobe *old_p; |
442 | 454 | ||
443 | if ((ret = arch_prepare_kprobe(p)) != 0) { | 455 | if ((ret = in_kprobes_functions((unsigned long) p->addr)) != 0) |
456 | return ret; | ||
457 | if ((ret = arch_prepare_kprobe(p)) != 0) | ||
444 | goto rm_kprobe; | 458 | goto rm_kprobe; |
445 | } | 459 | |
446 | spin_lock_irqsave(&kprobe_lock, flags); | 460 | spin_lock_irqsave(&kprobe_lock, flags); |
447 | old_p = get_kprobe(p->addr); | 461 | old_p = get_kprobe(p->addr); |
448 | p->nmissed = 0; | 462 | p->nmissed = 0; |
@@ -466,7 +480,7 @@ rm_kprobe: | |||
466 | return ret; | 480 | return ret; |
467 | } | 481 | } |
468 | 482 | ||
469 | void unregister_kprobe(struct kprobe *p) | 483 | void __kprobes unregister_kprobe(struct kprobe *p) |
470 | { | 484 | { |
471 | unsigned long flags; | 485 | unsigned long flags; |
472 | struct kprobe *old_p; | 486 | struct kprobe *old_p; |
@@ -487,7 +501,7 @@ static struct notifier_block kprobe_exceptions_nb = { | |||
487 | .priority = 0x7fffffff /* we need to notified first */ | 501 | .priority = 0x7fffffff /* we need to notified first */ |
488 | }; | 502 | }; |
489 | 503 | ||
490 | int register_jprobe(struct jprobe *jp) | 504 | int __kprobes register_jprobe(struct jprobe *jp) |
491 | { | 505 | { |
492 | /* Todo: Verify probepoint is a function entry point */ | 506 | /* Todo: Verify probepoint is a function entry point */ |
493 | jp->kp.pre_handler = setjmp_pre_handler; | 507 | jp->kp.pre_handler = setjmp_pre_handler; |
@@ -496,14 +510,14 @@ int register_jprobe(struct jprobe *jp) | |||
496 | return register_kprobe(&jp->kp); | 510 | return register_kprobe(&jp->kp); |
497 | } | 511 | } |
498 | 512 | ||
499 | void unregister_jprobe(struct jprobe *jp) | 513 | void __kprobes unregister_jprobe(struct jprobe *jp) |
500 | { | 514 | { |
501 | unregister_kprobe(&jp->kp); | 515 | unregister_kprobe(&jp->kp); |
502 | } | 516 | } |
503 | 517 | ||
504 | #ifdef ARCH_SUPPORTS_KRETPROBES | 518 | #ifdef ARCH_SUPPORTS_KRETPROBES |
505 | 519 | ||
506 | int register_kretprobe(struct kretprobe *rp) | 520 | int __kprobes register_kretprobe(struct kretprobe *rp) |
507 | { | 521 | { |
508 | int ret = 0; | 522 | int ret = 0; |
509 | struct kretprobe_instance *inst; | 523 | struct kretprobe_instance *inst; |
@@ -540,14 +554,14 @@ int register_kretprobe(struct kretprobe *rp) | |||
540 | 554 | ||
541 | #else /* ARCH_SUPPORTS_KRETPROBES */ | 555 | #else /* ARCH_SUPPORTS_KRETPROBES */ |
542 | 556 | ||
543 | int register_kretprobe(struct kretprobe *rp) | 557 | int __kprobes register_kretprobe(struct kretprobe *rp) |
544 | { | 558 | { |
545 | return -ENOSYS; | 559 | return -ENOSYS; |
546 | } | 560 | } |
547 | 561 | ||
548 | #endif /* ARCH_SUPPORTS_KRETPROBES */ | 562 | #endif /* ARCH_SUPPORTS_KRETPROBES */ |
549 | 563 | ||
550 | void unregister_kretprobe(struct kretprobe *rp) | 564 | void __kprobes unregister_kretprobe(struct kretprobe *rp) |
551 | { | 565 | { |
552 | unsigned long flags; | 566 | unsigned long flags; |
553 | struct kretprobe_instance *ri; | 567 | struct kretprobe_instance *ri; |