diff options
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r-- | kernel/kprobes.c | 32 |
1 files changed, 18 insertions, 14 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index f14ccd35e9b6..f1c0e61a2cb4 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -431,7 +431,7 @@ static int __kprobes register_aggr_kprobe(struct kprobe *old_p, | |||
431 | copy_kprobe(old_p, p); | 431 | copy_kprobe(old_p, p); |
432 | ret = add_new_kprobe(old_p, p); | 432 | ret = add_new_kprobe(old_p, p); |
433 | } else { | 433 | } else { |
434 | ap = kcalloc(1, sizeof(struct kprobe), GFP_ATOMIC); | 434 | ap = kcalloc(1, sizeof(struct kprobe), GFP_KERNEL); |
435 | if (!ap) | 435 | if (!ap) |
436 | return -ENOMEM; | 436 | return -ENOMEM; |
437 | add_aggr_kprobe(ap, old_p); | 437 | add_aggr_kprobe(ap, old_p); |
@@ -491,7 +491,8 @@ out: | |||
491 | void __kprobes unregister_kprobe(struct kprobe *p) | 491 | void __kprobes unregister_kprobe(struct kprobe *p) |
492 | { | 492 | { |
493 | struct module *mod; | 493 | struct module *mod; |
494 | struct kprobe *old_p, *cleanup_p; | 494 | struct kprobe *old_p, *list_p; |
495 | int cleanup_p; | ||
495 | 496 | ||
496 | down(&kprobe_mutex); | 497 | down(&kprobe_mutex); |
497 | old_p = get_kprobe(p->addr); | 498 | old_p = get_kprobe(p->addr); |
@@ -499,22 +500,25 @@ void __kprobes unregister_kprobe(struct kprobe *p) | |||
499 | up(&kprobe_mutex); | 500 | up(&kprobe_mutex); |
500 | return; | 501 | return; |
501 | } | 502 | } |
502 | 503 | if (p != old_p) { | |
503 | if ((old_p->pre_handler == aggr_pre_handler) && | 504 | list_for_each_entry_rcu(list_p, &old_p->list, list) |
505 | if (list_p == p) | ||
506 | /* kprobe p is a valid probe */ | ||
507 | goto valid_p; | ||
508 | up(&kprobe_mutex); | ||
509 | return; | ||
510 | } | ||
511 | valid_p: | ||
512 | if ((old_p == p) || ((old_p->pre_handler == aggr_pre_handler) && | ||
504 | (p->list.next == &old_p->list) && | 513 | (p->list.next == &old_p->list) && |
505 | (p->list.prev == &old_p->list)) { | 514 | (p->list.prev == &old_p->list))) { |
506 | /* Only one element in the aggregate list */ | 515 | /* Only probe on the hash list */ |
507 | arch_disarm_kprobe(p); | 516 | arch_disarm_kprobe(p); |
508 | hlist_del_rcu(&old_p->hlist); | 517 | hlist_del_rcu(&old_p->hlist); |
509 | cleanup_p = old_p; | 518 | cleanup_p = 1; |
510 | } else if (old_p == p) { | ||
511 | /* Only one kprobe element in the hash list */ | ||
512 | arch_disarm_kprobe(p); | ||
513 | hlist_del_rcu(&p->hlist); | ||
514 | cleanup_p = p; | ||
515 | } else { | 519 | } else { |
516 | list_del_rcu(&p->list); | 520 | list_del_rcu(&p->list); |
517 | cleanup_p = NULL; | 521 | cleanup_p = 0; |
518 | } | 522 | } |
519 | 523 | ||
520 | up(&kprobe_mutex); | 524 | up(&kprobe_mutex); |
@@ -524,7 +528,7 @@ void __kprobes unregister_kprobe(struct kprobe *p) | |||
524 | module_put(mod); | 528 | module_put(mod); |
525 | 529 | ||
526 | if (cleanup_p) { | 530 | if (cleanup_p) { |
527 | if (cleanup_p->pre_handler == aggr_pre_handler) { | 531 | if (p != old_p) { |
528 | list_del_rcu(&p->list); | 532 | list_del_rcu(&p->list); |
529 | kfree(old_p); | 533 | kfree(old_p); |
530 | } | 534 | } |