diff options
-rw-r--r-- | include/asm-i386/kprobes.h | 1 | ||||
-rw-r--r-- | include/asm-ia64/kprobes.h | 1 | ||||
-rw-r--r-- | include/asm-powerpc/kprobes.h | 2 | ||||
-rw-r--r-- | include/asm-sparc64/kprobes.h | 1 | ||||
-rw-r--r-- | include/asm-x86_64/kprobes.h | 1 | ||||
-rw-r--r-- | kernel/kprobes.c | 30 |
6 files changed, 29 insertions, 7 deletions
diff --git a/include/asm-i386/kprobes.h b/include/asm-i386/kprobes.h index 57d157c5cf89..0730a20f6db8 100644 --- a/include/asm-i386/kprobes.h +++ b/include/asm-i386/kprobes.h | |||
@@ -44,6 +44,7 @@ typedef u8 kprobe_opcode_t; | |||
44 | 44 | ||
45 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry | 45 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry |
46 | #define ARCH_SUPPORTS_KRETPROBES | 46 | #define ARCH_SUPPORTS_KRETPROBES |
47 | #define ARCH_INACTIVE_KPROBE_COUNT 0 | ||
47 | 48 | ||
48 | void arch_remove_kprobe(struct kprobe *p); | 49 | void arch_remove_kprobe(struct kprobe *p); |
49 | void kretprobe_trampoline(void); | 50 | void kretprobe_trampoline(void); |
diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h index 8c0fc227f0fb..2418a787c405 100644 --- a/include/asm-ia64/kprobes.h +++ b/include/asm-ia64/kprobes.h | |||
@@ -82,6 +82,7 @@ struct kprobe_ctlblk { | |||
82 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry | 82 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry |
83 | 83 | ||
84 | #define ARCH_SUPPORTS_KRETPROBES | 84 | #define ARCH_SUPPORTS_KRETPROBES |
85 | #define ARCH_INACTIVE_KPROBE_COUNT 1 | ||
85 | 86 | ||
86 | #define SLOT0_OPCODE_SHIFT (37) | 87 | #define SLOT0_OPCODE_SHIFT (37) |
87 | #define SLOT1_p1_OPCODE_SHIFT (37 - (64-46)) | 88 | #define SLOT1_p1_OPCODE_SHIFT (37 - (64-46)) |
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h index f466bc804f41..2d0af52c823d 100644 --- a/include/asm-powerpc/kprobes.h +++ b/include/asm-powerpc/kprobes.h | |||
@@ -50,6 +50,8 @@ typedef unsigned int kprobe_opcode_t; | |||
50 | IS_TWI(instr) || IS_TDI(instr)) | 50 | IS_TWI(instr) || IS_TDI(instr)) |
51 | 51 | ||
52 | #define ARCH_SUPPORTS_KRETPROBES | 52 | #define ARCH_SUPPORTS_KRETPROBES |
53 | #define ARCH_INACTIVE_KPROBE_COUNT 1 | ||
54 | |||
53 | void kretprobe_trampoline(void); | 55 | void kretprobe_trampoline(void); |
54 | extern void arch_remove_kprobe(struct kprobe *p); | 56 | extern void arch_remove_kprobe(struct kprobe *p); |
55 | 57 | ||
diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h index e9bb26f770ed..15065af566c2 100644 --- a/include/asm-sparc64/kprobes.h +++ b/include/asm-sparc64/kprobes.h | |||
@@ -12,6 +12,7 @@ typedef u32 kprobe_opcode_t; | |||
12 | 12 | ||
13 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry | 13 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry |
14 | #define arch_remove_kprobe(p) do {} while (0) | 14 | #define arch_remove_kprobe(p) do {} while (0) |
15 | #define ARCH_INACTIVE_KPROBE_COUNT 0 | ||
15 | 16 | ||
16 | /* Architecture specific copy of original instruction*/ | 17 | /* Architecture specific copy of original instruction*/ |
17 | struct arch_specific_insn { | 18 | struct arch_specific_insn { |
diff --git a/include/asm-x86_64/kprobes.h b/include/asm-x86_64/kprobes.h index 98a1e95ddb98..d36febd9bb18 100644 --- a/include/asm-x86_64/kprobes.h +++ b/include/asm-x86_64/kprobes.h | |||
@@ -43,6 +43,7 @@ typedef u8 kprobe_opcode_t; | |||
43 | 43 | ||
44 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry | 44 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry |
45 | #define ARCH_SUPPORTS_KRETPROBES | 45 | #define ARCH_SUPPORTS_KRETPROBES |
46 | #define ARCH_INACTIVE_KPROBE_COUNT 1 | ||
46 | 47 | ||
47 | void kretprobe_trampoline(void); | 48 | void kretprobe_trampoline(void); |
48 | extern void arch_remove_kprobe(struct kprobe *p); | 49 | extern void arch_remove_kprobe(struct kprobe *p); |
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 | ||