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 |
