diff options
Diffstat (limited to 'kernel/kprobes.c')
-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 | ||