diff options
-rw-r--r-- | include/linux/kprobes.h | 9 | ||||
-rw-r--r-- | kernel/kprobes.c | 65 |
2 files changed, 65 insertions, 9 deletions
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 94c855a236ae..1036631ff4fa 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h | |||
@@ -240,6 +240,8 @@ int setjmp_pre_handler(struct kprobe *, struct pt_regs *); | |||
240 | int longjmp_break_handler(struct kprobe *, struct pt_regs *); | 240 | int longjmp_break_handler(struct kprobe *, struct pt_regs *); |
241 | int register_jprobe(struct jprobe *p); | 241 | int register_jprobe(struct jprobe *p); |
242 | void unregister_jprobe(struct jprobe *p); | 242 | void unregister_jprobe(struct jprobe *p); |
243 | int register_jprobes(struct jprobe **jps, int num); | ||
244 | void unregister_jprobes(struct jprobe **jps, int num); | ||
243 | void jprobe_return(void); | 245 | void jprobe_return(void); |
244 | unsigned long arch_deref_entry_point(void *); | 246 | unsigned long arch_deref_entry_point(void *); |
245 | 247 | ||
@@ -279,9 +281,16 @@ static inline int register_jprobe(struct jprobe *p) | |||
279 | { | 281 | { |
280 | return -ENOSYS; | 282 | return -ENOSYS; |
281 | } | 283 | } |
284 | static inline int register_jprobes(struct jprobe **jps, int num) | ||
285 | { | ||
286 | return -ENOSYS; | ||
287 | } | ||
282 | static inline void unregister_jprobe(struct jprobe *p) | 288 | static inline void unregister_jprobe(struct jprobe *p) |
283 | { | 289 | { |
284 | } | 290 | } |
291 | static inline void unregister_jprobes(struct jprobe **jps, int num) | ||
292 | { | ||
293 | } | ||
285 | static inline void jprobe_return(void) | 294 | static inline void jprobe_return(void) |
286 | { | 295 | { |
287 | } | 296 | } |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 5e3144ad9b64..1e0250cb9486 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -755,24 +755,69 @@ unsigned long __weak arch_deref_entry_point(void *entry) | |||
755 | return (unsigned long)entry; | 755 | return (unsigned long)entry; |
756 | } | 756 | } |
757 | 757 | ||
758 | int __kprobes register_jprobe(struct jprobe *jp) | 758 | static int __register_jprobes(struct jprobe **jps, int num, |
759 | unsigned long called_from) | ||
759 | { | 760 | { |
760 | unsigned long addr = arch_deref_entry_point(jp->entry); | 761 | struct jprobe *jp; |
762 | int ret = 0, i; | ||
761 | 763 | ||
762 | if (!kernel_text_address(addr)) | 764 | if (num <= 0) |
763 | return -EINVAL; | 765 | return -EINVAL; |
766 | for (i = 0; i < num; i++) { | ||
767 | unsigned long addr; | ||
768 | jp = jps[i]; | ||
769 | addr = arch_deref_entry_point(jp->entry); | ||
770 | |||
771 | if (!kernel_text_address(addr)) | ||
772 | ret = -EINVAL; | ||
773 | else { | ||
774 | /* Todo: Verify probepoint is a function entry point */ | ||
775 | jp->kp.pre_handler = setjmp_pre_handler; | ||
776 | jp->kp.break_handler = longjmp_break_handler; | ||
777 | ret = __register_kprobe(&jp->kp, called_from); | ||
778 | } | ||
779 | if (ret < 0 && i > 0) { | ||
780 | unregister_jprobes(jps, i); | ||
781 | break; | ||
782 | } | ||
783 | } | ||
784 | return ret; | ||
785 | } | ||
764 | 786 | ||
765 | /* Todo: Verify probepoint is a function entry point */ | 787 | int __kprobes register_jprobe(struct jprobe *jp) |
766 | jp->kp.pre_handler = setjmp_pre_handler; | 788 | { |
767 | jp->kp.break_handler = longjmp_break_handler; | 789 | return __register_jprobes(&jp, 1, |
768 | |||
769 | return __register_kprobe(&jp->kp, | ||
770 | (unsigned long)__builtin_return_address(0)); | 790 | (unsigned long)__builtin_return_address(0)); |
771 | } | 791 | } |
772 | 792 | ||
773 | void __kprobes unregister_jprobe(struct jprobe *jp) | 793 | void __kprobes unregister_jprobe(struct jprobe *jp) |
774 | { | 794 | { |
775 | unregister_kprobe(&jp->kp); | 795 | unregister_jprobes(&jp, 1); |
796 | } | ||
797 | |||
798 | int __kprobes register_jprobes(struct jprobe **jps, int num) | ||
799 | { | ||
800 | return __register_jprobes(jps, num, | ||
801 | (unsigned long)__builtin_return_address(0)); | ||
802 | } | ||
803 | |||
804 | void __kprobes unregister_jprobes(struct jprobe **jps, int num) | ||
805 | { | ||
806 | int i; | ||
807 | |||
808 | if (num <= 0) | ||
809 | return; | ||
810 | mutex_lock(&kprobe_mutex); | ||
811 | for (i = 0; i < num; i++) | ||
812 | if (__unregister_kprobe_top(&jps[i]->kp) < 0) | ||
813 | jps[i]->kp.addr = NULL; | ||
814 | mutex_unlock(&kprobe_mutex); | ||
815 | |||
816 | synchronize_sched(); | ||
817 | for (i = 0; i < num; i++) { | ||
818 | if (jps[i]->kp.addr) | ||
819 | __unregister_kprobe_bottom(&jps[i]->kp); | ||
820 | } | ||
776 | } | 821 | } |
777 | 822 | ||
778 | #ifdef CONFIG_KRETPROBES | 823 | #ifdef CONFIG_KRETPROBES |
@@ -1236,6 +1281,8 @@ EXPORT_SYMBOL_GPL(register_kprobes); | |||
1236 | EXPORT_SYMBOL_GPL(unregister_kprobes); | 1281 | EXPORT_SYMBOL_GPL(unregister_kprobes); |
1237 | EXPORT_SYMBOL_GPL(register_jprobe); | 1282 | EXPORT_SYMBOL_GPL(register_jprobe); |
1238 | EXPORT_SYMBOL_GPL(unregister_jprobe); | 1283 | EXPORT_SYMBOL_GPL(unregister_jprobe); |
1284 | EXPORT_SYMBOL_GPL(register_jprobes); | ||
1285 | EXPORT_SYMBOL_GPL(unregister_jprobes); | ||
1239 | #ifdef CONFIG_KPROBES | 1286 | #ifdef CONFIG_KPROBES |
1240 | EXPORT_SYMBOL_GPL(jprobe_return); | 1287 | EXPORT_SYMBOL_GPL(jprobe_return); |
1241 | #endif | 1288 | #endif |