diff options
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r-- | kernel/kprobes.c | 36 |
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 */ | ||
250 | void __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 */ |
250 | struct kretprobe_instance __kprobes *get_free_rp_inst(struct kretprobe *rp) | 263 | struct 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: | |||
488 | rm_kprobe: | 505 | rm_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); |