diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/kprobes.c | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 507f26e7ae7c..64aab081153b 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
| @@ -47,11 +47,17 @@ | |||
| 47 | 47 | ||
| 48 | static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; | 48 | static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; |
| 49 | static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; | 49 | static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; |
| 50 | static atomic_t kprobe_count; | ||
| 50 | 51 | ||
| 51 | DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */ | 52 | DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */ |
| 52 | DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */ | 53 | DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */ |
| 53 | static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL; | 54 | static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL; |
| 54 | 55 | ||
| 56 | static struct notifier_block kprobe_page_fault_nb = { | ||
| 57 | .notifier_call = kprobe_exceptions_notify, | ||
| 58 | .priority = 0x7fffffff /* we need to notified first */ | ||
| 59 | }; | ||
| 60 | |||
| 55 | #ifdef __ARCH_WANT_KPROBES_INSN_SLOT | 61 | #ifdef __ARCH_WANT_KPROBES_INSN_SLOT |
| 56 | /* | 62 | /* |
| 57 | * kprobe->ainsn.insn points to the copy of the instruction to be | 63 | * kprobe->ainsn.insn points to the copy of the instruction to be |
| @@ -465,6 +471,8 @@ static int __kprobes __register_kprobe(struct kprobe *p, | |||
| 465 | old_p = get_kprobe(p->addr); | 471 | old_p = get_kprobe(p->addr); |
| 466 | if (old_p) { | 472 | if (old_p) { |
| 467 | ret = register_aggr_kprobe(old_p, p); | 473 | ret = register_aggr_kprobe(old_p, p); |
| 474 | if (!ret) | ||
| 475 | atomic_inc(&kprobe_count); | ||
| 468 | goto out; | 476 | goto out; |
| 469 | } | 477 | } |
| 470 | 478 | ||
| @@ -475,6 +483,10 @@ static int __kprobes __register_kprobe(struct kprobe *p, | |||
| 475 | hlist_add_head_rcu(&p->hlist, | 483 | hlist_add_head_rcu(&p->hlist, |
| 476 | &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]); | 484 | &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]); |
| 477 | 485 | ||
| 486 | if (atomic_add_return(1, &kprobe_count) == \ | ||
| 487 | (ARCH_INACTIVE_KPROBE_COUNT + 1)) | ||
| 488 | register_page_fault_notifier(&kprobe_page_fault_nb); | ||
| 489 | |||
| 478 | arch_arm_kprobe(p); | 490 | arch_arm_kprobe(p); |
| 479 | 491 | ||
| 480 | out: | 492 | out: |
| @@ -553,6 +565,16 @@ valid_p: | |||
| 553 | } | 565 | } |
| 554 | mutex_unlock(&kprobe_mutex); | 566 | mutex_unlock(&kprobe_mutex); |
| 555 | } | 567 | } |
| 568 | |||
| 569 | /* Call unregister_page_fault_notifier() | ||
| 570 | * if no probes are active | ||
| 571 | */ | ||
| 572 | mutex_lock(&kprobe_mutex); | ||
| 573 | if (atomic_add_return(-1, &kprobe_count) == \ | ||
| 574 | ARCH_INACTIVE_KPROBE_COUNT) | ||
| 575 | unregister_page_fault_notifier(&kprobe_page_fault_nb); | ||
| 576 | mutex_unlock(&kprobe_mutex); | ||
| 577 | return; | ||
| 556 | } | 578 | } |
| 557 | 579 | ||
| 558 | static struct notifier_block kprobe_exceptions_nb = { | 580 | static struct notifier_block kprobe_exceptions_nb = { |
| @@ -560,10 +582,6 @@ static struct notifier_block kprobe_exceptions_nb = { | |||
| 560 | .priority = 0x7fffffff /* we need to be notified first */ | 582 | .priority = 0x7fffffff /* we need to be notified first */ |
| 561 | }; | 583 | }; |
| 562 | 584 | ||
| 563 | static struct notifier_block kprobe_page_fault_nb = { | ||
| 564 | .notifier_call = kprobe_exceptions_notify, | ||
| 565 | .priority = 0x7fffffff /* we need to notified first */ | ||
| 566 | }; | ||
| 567 | 585 | ||
| 568 | int __kprobes register_jprobe(struct jprobe *jp) | 586 | int __kprobes register_jprobe(struct jprobe *jp) |
| 569 | { | 587 | { |
| @@ -673,14 +691,12 @@ static int __init init_kprobes(void) | |||
| 673 | INIT_HLIST_HEAD(&kprobe_table[i]); | 691 | INIT_HLIST_HEAD(&kprobe_table[i]); |
| 674 | INIT_HLIST_HEAD(&kretprobe_inst_table[i]); | 692 | INIT_HLIST_HEAD(&kretprobe_inst_table[i]); |
| 675 | } | 693 | } |
| 694 | atomic_set(&kprobe_count, 0); | ||
| 676 | 695 | ||
| 677 | err = arch_init_kprobes(); | 696 | err = arch_init_kprobes(); |
| 678 | if (!err) | 697 | if (!err) |
| 679 | err = register_die_notifier(&kprobe_exceptions_nb); | 698 | err = register_die_notifier(&kprobe_exceptions_nb); |
| 680 | 699 | ||
| 681 | if (!err) | ||
| 682 | err = register_page_fault_notifier(&kprobe_page_fault_nb); | ||
| 683 | |||
| 684 | return err; | 700 | return err; |
| 685 | } | 701 | } |
| 686 | 702 | ||
