aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r--kernel/kprobes.c36
1 files changed, 30 insertions, 6 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 5beda378cc75..3bb71e63a37e 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -246,6 +246,19 @@ static int __kprobes aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
246 return ret; 246 return ret;
247} 247}
248 248
249/* Walks the list and increments nmissed count for multiprobe case */
250void __kprobes kprobes_inc_nmissed_count(struct kprobe *p)
251{
252 struct kprobe *kp;
253 if (p->pre_handler != aggr_pre_handler) {
254 p->nmissed++;
255 } else {
256 list_for_each_entry_rcu(kp, &p->list, list)
257 kp->nmissed++;
258 }
259 return;
260}
261
249/* Called with kretprobe_lock held */ 262/* Called with kretprobe_lock held */
250struct kretprobe_instance __kprobes *get_free_rp_inst(struct kretprobe *rp) 263struct kretprobe_instance __kprobes *get_free_rp_inst(struct kretprobe *rp)
251{ 264{
@@ -399,10 +412,7 @@ static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
399 INIT_LIST_HEAD(&ap->list); 412 INIT_LIST_HEAD(&ap->list);
400 list_add_rcu(&p->list, &ap->list); 413 list_add_rcu(&p->list, &ap->list);
401 414
402 INIT_HLIST_NODE(&ap->hlist); 415 hlist_replace_rcu(&p->hlist, &ap->hlist);
403 hlist_del_rcu(&p->hlist);
404 hlist_add_head_rcu(&ap->hlist,
405 &kprobe_table[hash_ptr(ap->addr, KPROBE_HASH_BITS)]);
406} 416}
407 417
408/* 418/*
@@ -462,9 +472,16 @@ int __kprobes register_kprobe(struct kprobe *p)
462 int ret = 0; 472 int ret = 0;
463 unsigned long flags = 0; 473 unsigned long flags = 0;
464 struct kprobe *old_p; 474 struct kprobe *old_p;
475 struct module *mod;
476
477 if ((!kernel_text_address((unsigned long) p->addr)) ||
478 in_kprobes_functions((unsigned long) p->addr))
479 return -EINVAL;
480
481 if ((mod = module_text_address((unsigned long) p->addr)) &&
482 (unlikely(!try_module_get(mod))))
483 return -EINVAL;
465 484
466 if ((ret = in_kprobes_functions((unsigned long) p->addr)) != 0)
467 return ret;
468 if ((ret = arch_prepare_kprobe(p)) != 0) 485 if ((ret = arch_prepare_kprobe(p)) != 0)
469 goto rm_kprobe; 486 goto rm_kprobe;
470 487
@@ -488,6 +505,8 @@ out:
488rm_kprobe: 505rm_kprobe:
489 if (ret == -EEXIST) 506 if (ret == -EEXIST)
490 arch_remove_kprobe(p); 507 arch_remove_kprobe(p);
508 if (ret && mod)
509 module_put(mod);
491 return ret; 510 return ret;
492} 511}
493 512
@@ -495,6 +514,7 @@ void __kprobes unregister_kprobe(struct kprobe *p)
495{ 514{
496 unsigned long flags; 515 unsigned long flags;
497 struct kprobe *old_p; 516 struct kprobe *old_p;
517 struct module *mod;
498 518
499 spin_lock_irqsave(&kprobe_lock, flags); 519 spin_lock_irqsave(&kprobe_lock, flags);
500 old_p = get_kprobe(p->addr); 520 old_p = get_kprobe(p->addr);
@@ -506,6 +526,10 @@ void __kprobes unregister_kprobe(struct kprobe *p)
506 cleanup_kprobe(p, flags); 526 cleanup_kprobe(p, flags);
507 527
508 synchronize_sched(); 528 synchronize_sched();
529
530 if ((mod = module_text_address((unsigned long)p->addr)))
531 module_put(mod);
532
509 if (old_p->pre_handler == aggr_pre_handler && 533 if (old_p->pre_handler == aggr_pre_handler &&
510 list_empty(&old_p->list)) 534 list_empty(&old_p->list))
511 kfree(old_p); 535 kfree(old_p);