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); | 
