aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r--kernel/kprobes.c53
1 files changed, 43 insertions, 10 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 3f57dfdc8f92..610c837ad9e0 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -37,6 +37,7 @@
37#include <linux/slab.h> 37#include <linux/slab.h>
38#include <linux/module.h> 38#include <linux/module.h>
39#include <linux/moduleloader.h> 39#include <linux/moduleloader.h>
40#include <linux/kallsyms.h>
40#include <asm-generic/sections.h> 41#include <asm-generic/sections.h>
41#include <asm/cacheflush.h> 42#include <asm/cacheflush.h>
42#include <asm/errno.h> 43#include <asm/errno.h>
@@ -45,6 +46,16 @@
45#define KPROBE_HASH_BITS 6 46#define KPROBE_HASH_BITS 6
46#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS) 47#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
47 48
49
50/*
51 * Some oddball architectures like 64bit powerpc have function descriptors
52 * so this must be overridable.
53 */
54#ifndef kprobe_lookup_name
55#define kprobe_lookup_name(name, addr) \
56 addr = ((kprobe_opcode_t *)(kallsyms_lookup_name(name)))
57#endif
58
48static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; 59static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
49static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; 60static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
50static atomic_t kprobe_count; 61static atomic_t kprobe_count;
@@ -308,7 +319,8 @@ void __kprobes add_rp_inst(struct kretprobe_instance *ri)
308} 319}
309 320
310/* Called with kretprobe_lock held */ 321/* Called with kretprobe_lock held */
311void __kprobes recycle_rp_inst(struct kretprobe_instance *ri) 322void __kprobes recycle_rp_inst(struct kretprobe_instance *ri,
323 struct hlist_head *head)
312{ 324{
313 /* remove rp inst off the rprobe_inst_table */ 325 /* remove rp inst off the rprobe_inst_table */
314 hlist_del(&ri->hlist); 326 hlist_del(&ri->hlist);
@@ -320,7 +332,7 @@ void __kprobes recycle_rp_inst(struct kretprobe_instance *ri)
320 hlist_add_head(&ri->uflist, &ri->rp->free_instances); 332 hlist_add_head(&ri->uflist, &ri->rp->free_instances);
321 } else 333 } else
322 /* Unregistering */ 334 /* Unregistering */
323 kfree(ri); 335 hlist_add_head(&ri->hlist, head);
324} 336}
325 337
326struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk) 338struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk)
@@ -336,18 +348,24 @@ struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk)
336 */ 348 */
337void __kprobes kprobe_flush_task(struct task_struct *tk) 349void __kprobes kprobe_flush_task(struct task_struct *tk)
338{ 350{
339 struct kretprobe_instance *ri; 351 struct kretprobe_instance *ri;
340 struct hlist_head *head; 352 struct hlist_head *head, empty_rp;
341 struct hlist_node *node, *tmp; 353 struct hlist_node *node, *tmp;
342 unsigned long flags = 0; 354 unsigned long flags = 0;
343 355
356 INIT_HLIST_HEAD(&empty_rp);
344 spin_lock_irqsave(&kretprobe_lock, flags); 357 spin_lock_irqsave(&kretprobe_lock, flags);
345 head = kretprobe_inst_table_head(tk); 358 head = kretprobe_inst_table_head(tk);
346 hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { 359 hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
347 if (ri->task == tk) 360 if (ri->task == tk)
348 recycle_rp_inst(ri); 361 recycle_rp_inst(ri, &empty_rp);
349 } 362 }
350 spin_unlock_irqrestore(&kretprobe_lock, flags); 363 spin_unlock_irqrestore(&kretprobe_lock, flags);
364
365 hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
366 hlist_del(&ri->hlist);
367 kfree(ri);
368 }
351} 369}
352 370
353static inline void free_rp_inst(struct kretprobe *rp) 371static inline void free_rp_inst(struct kretprobe *rp)
@@ -447,6 +465,21 @@ static int __kprobes __register_kprobe(struct kprobe *p,
447 struct kprobe *old_p; 465 struct kprobe *old_p;
448 struct module *probed_mod; 466 struct module *probed_mod;
449 467
468 /*
469 * If we have a symbol_name argument look it up,
470 * and add it to the address. That way the addr
471 * field can either be global or relative to a symbol.
472 */
473 if (p->symbol_name) {
474 if (p->addr)
475 return -EINVAL;
476 kprobe_lookup_name(p->symbol_name, p->addr);
477 }
478
479 if (!p->addr)
480 return -EINVAL;
481 p->addr = (kprobe_opcode_t *)(((char *)p->addr)+ p->offset);
482
450 if ((!kernel_text_address((unsigned long) p->addr)) || 483 if ((!kernel_text_address((unsigned long) p->addr)) ||
451 in_kprobes_functions((unsigned long) p->addr)) 484 in_kprobes_functions((unsigned long) p->addr))
452 return -EINVAL; 485 return -EINVAL;
@@ -488,7 +521,7 @@ static int __kprobes __register_kprobe(struct kprobe *p,
488 (ARCH_INACTIVE_KPROBE_COUNT + 1)) 521 (ARCH_INACTIVE_KPROBE_COUNT + 1))
489 register_page_fault_notifier(&kprobe_page_fault_nb); 522 register_page_fault_notifier(&kprobe_page_fault_nb);
490 523
491 arch_arm_kprobe(p); 524 arch_arm_kprobe(p);
492 525
493out: 526out:
494 mutex_unlock(&kprobe_mutex); 527 mutex_unlock(&kprobe_mutex);