diff options
Diffstat (limited to 'kernel/kprobes.c')
| -rw-r--r-- | kernel/kprobes.c | 72 |
1 files changed, 50 insertions, 22 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 5240d75f4c60..e5342a344c43 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
| @@ -90,6 +90,9 @@ static spinlock_t *kretprobe_table_lock_ptr(unsigned long hash) | |||
| 90 | */ | 90 | */ |
| 91 | static struct kprobe_blackpoint kprobe_blacklist[] = { | 91 | static struct kprobe_blackpoint kprobe_blacklist[] = { |
| 92 | {"preempt_schedule",}, | 92 | {"preempt_schedule",}, |
| 93 | {"native_get_debugreg",}, | ||
| 94 | {"irq_entries_start",}, | ||
| 95 | {"common_interrupt",}, | ||
| 93 | {NULL} /* Terminator */ | 96 | {NULL} /* Terminator */ |
| 94 | }; | 97 | }; |
| 95 | 98 | ||
| @@ -673,6 +676,40 @@ static kprobe_opcode_t __kprobes *kprobe_addr(struct kprobe *p) | |||
| 673 | return (kprobe_opcode_t *)(((char *)addr) + p->offset); | 676 | return (kprobe_opcode_t *)(((char *)addr) + p->offset); |
| 674 | } | 677 | } |
| 675 | 678 | ||
| 679 | /* Check passed kprobe is valid and return kprobe in kprobe_table. */ | ||
| 680 | static struct kprobe * __kprobes __get_valid_kprobe(struct kprobe *p) | ||
| 681 | { | ||
| 682 | struct kprobe *old_p, *list_p; | ||
| 683 | |||
| 684 | old_p = get_kprobe(p->addr); | ||
| 685 | if (unlikely(!old_p)) | ||
| 686 | return NULL; | ||
| 687 | |||
| 688 | if (p != old_p) { | ||
| 689 | list_for_each_entry_rcu(list_p, &old_p->list, list) | ||
| 690 | if (list_p == p) | ||
| 691 | /* kprobe p is a valid probe */ | ||
| 692 | goto valid; | ||
| 693 | return NULL; | ||
| 694 | } | ||
| 695 | valid: | ||
| 696 | return old_p; | ||
| 697 | } | ||
| 698 | |||
| 699 | /* Return error if the kprobe is being re-registered */ | ||
| 700 | static inline int check_kprobe_rereg(struct kprobe *p) | ||
| 701 | { | ||
| 702 | int ret = 0; | ||
| 703 | struct kprobe *old_p; | ||
| 704 | |||
| 705 | mutex_lock(&kprobe_mutex); | ||
| 706 | old_p = __get_valid_kprobe(p); | ||
| 707 | if (old_p) | ||
| 708 | ret = -EINVAL; | ||
| 709 | mutex_unlock(&kprobe_mutex); | ||
| 710 | return ret; | ||
| 711 | } | ||
| 712 | |||
| 676 | int __kprobes register_kprobe(struct kprobe *p) | 713 | int __kprobes register_kprobe(struct kprobe *p) |
| 677 | { | 714 | { |
| 678 | int ret = 0; | 715 | int ret = 0; |
| @@ -685,6 +722,10 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
| 685 | return -EINVAL; | 722 | return -EINVAL; |
| 686 | p->addr = addr; | 723 | p->addr = addr; |
| 687 | 724 | ||
| 725 | ret = check_kprobe_rereg(p); | ||
| 726 | if (ret) | ||
| 727 | return ret; | ||
| 728 | |||
| 688 | preempt_disable(); | 729 | preempt_disable(); |
| 689 | if (!kernel_text_address((unsigned long) p->addr) || | 730 | if (!kernel_text_address((unsigned long) p->addr) || |
| 690 | in_kprobes_functions((unsigned long) p->addr)) { | 731 | in_kprobes_functions((unsigned long) p->addr)) { |
| @@ -754,26 +795,6 @@ out: | |||
| 754 | } | 795 | } |
| 755 | EXPORT_SYMBOL_GPL(register_kprobe); | 796 | EXPORT_SYMBOL_GPL(register_kprobe); |
| 756 | 797 | ||
| 757 | /* Check passed kprobe is valid and return kprobe in kprobe_table. */ | ||
| 758 | static struct kprobe * __kprobes __get_valid_kprobe(struct kprobe *p) | ||
| 759 | { | ||
| 760 | struct kprobe *old_p, *list_p; | ||
| 761 | |||
| 762 | old_p = get_kprobe(p->addr); | ||
| 763 | if (unlikely(!old_p)) | ||
| 764 | return NULL; | ||
| 765 | |||
| 766 | if (p != old_p) { | ||
| 767 | list_for_each_entry_rcu(list_p, &old_p->list, list) | ||
| 768 | if (list_p == p) | ||
| 769 | /* kprobe p is a valid probe */ | ||
| 770 | goto valid; | ||
| 771 | return NULL; | ||
| 772 | } | ||
| 773 | valid: | ||
| 774 | return old_p; | ||
| 775 | } | ||
| 776 | |||
| 777 | /* | 798 | /* |
| 778 | * Unregister a kprobe without a scheduler synchronization. | 799 | * Unregister a kprobe without a scheduler synchronization. |
| 779 | */ | 800 | */ |
| @@ -1014,9 +1035,9 @@ int __kprobes register_kretprobe(struct kretprobe *rp) | |||
| 1014 | /* Pre-allocate memory for max kretprobe instances */ | 1035 | /* Pre-allocate memory for max kretprobe instances */ |
| 1015 | if (rp->maxactive <= 0) { | 1036 | if (rp->maxactive <= 0) { |
| 1016 | #ifdef CONFIG_PREEMPT | 1037 | #ifdef CONFIG_PREEMPT |
| 1017 | rp->maxactive = max(10, 2 * NR_CPUS); | 1038 | rp->maxactive = max(10, 2 * num_possible_cpus()); |
| 1018 | #else | 1039 | #else |
| 1019 | rp->maxactive = NR_CPUS; | 1040 | rp->maxactive = num_possible_cpus(); |
| 1020 | #endif | 1041 | #endif |
| 1021 | } | 1042 | } |
| 1022 | spin_lock_init(&rp->lock); | 1043 | spin_lock_init(&rp->lock); |
| @@ -1141,6 +1162,13 @@ static void __kprobes kill_kprobe(struct kprobe *p) | |||
| 1141 | arch_remove_kprobe(p); | 1162 | arch_remove_kprobe(p); |
| 1142 | } | 1163 | } |
| 1143 | 1164 | ||
| 1165 | void __kprobes dump_kprobe(struct kprobe *kp) | ||
| 1166 | { | ||
| 1167 | printk(KERN_WARNING "Dumping kprobe:\n"); | ||
| 1168 | printk(KERN_WARNING "Name: %s\nAddress: %p\nOffset: %x\n", | ||
| 1169 | kp->symbol_name, kp->addr, kp->offset); | ||
| 1170 | } | ||
| 1171 | |||
| 1144 | /* Module notifier call back, checking kprobes on the module */ | 1172 | /* Module notifier call back, checking kprobes on the module */ |
| 1145 | static int __kprobes kprobes_module_callback(struct notifier_block *nb, | 1173 | static int __kprobes kprobes_module_callback(struct notifier_block *nb, |
| 1146 | unsigned long val, void *data) | 1174 | unsigned long val, void *data) |
