aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r--kernel/kprobes.c32
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:
491void __kprobes unregister_kprobe(struct kprobe *p) 491void __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 }
511valid_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 }