diff options
-rw-r--r-- | include/linux/kprobes.h | 9 | ||||
-rw-r--r-- | kernel/kprobes.c | 108 |
2 files changed, 97 insertions, 20 deletions
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 2ba7df645a84..94c855a236ae 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h | |||
@@ -245,6 +245,8 @@ unsigned long arch_deref_entry_point(void *); | |||
245 | 245 | ||
246 | int register_kretprobe(struct kretprobe *rp); | 246 | int register_kretprobe(struct kretprobe *rp); |
247 | void unregister_kretprobe(struct kretprobe *rp); | 247 | void unregister_kretprobe(struct kretprobe *rp); |
248 | int register_kretprobes(struct kretprobe **rps, int num); | ||
249 | void unregister_kretprobes(struct kretprobe **rps, int num); | ||
248 | 250 | ||
249 | void kprobe_flush_task(struct task_struct *tk); | 251 | void kprobe_flush_task(struct task_struct *tk); |
250 | void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head); | 252 | void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head); |
@@ -287,9 +289,16 @@ static inline int register_kretprobe(struct kretprobe *rp) | |||
287 | { | 289 | { |
288 | return -ENOSYS; | 290 | return -ENOSYS; |
289 | } | 291 | } |
292 | static inline int register_kretprobes(struct kretprobe **rps, int num) | ||
293 | { | ||
294 | return -ENOSYS; | ||
295 | } | ||
290 | static inline void unregister_kretprobe(struct kretprobe *rp) | 296 | static inline void unregister_kretprobe(struct kretprobe *rp) |
291 | { | 297 | { |
292 | } | 298 | } |
299 | static inline void unregister_kretprobes(struct kretprobe **rps, int num) | ||
300 | { | ||
301 | } | ||
293 | static inline void kprobe_flush_task(struct task_struct *tk) | 302 | static inline void kprobe_flush_task(struct task_struct *tk) |
294 | { | 303 | { |
295 | } | 304 | } |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 76275fc025a5..5e3144ad9b64 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -429,6 +429,21 @@ static inline void free_rp_inst(struct kretprobe *rp) | |||
429 | } | 429 | } |
430 | } | 430 | } |
431 | 431 | ||
432 | static void __kprobes cleanup_rp_inst(struct kretprobe *rp) | ||
433 | { | ||
434 | unsigned long flags; | ||
435 | struct kretprobe_instance *ri; | ||
436 | struct hlist_node *pos, *next; | ||
437 | /* No race here */ | ||
438 | spin_lock_irqsave(&kretprobe_lock, flags); | ||
439 | hlist_for_each_entry_safe(ri, pos, next, &rp->used_instances, uflist) { | ||
440 | ri->rp = NULL; | ||
441 | hlist_del(&ri->uflist); | ||
442 | } | ||
443 | spin_unlock_irqrestore(&kretprobe_lock, flags); | ||
444 | free_rp_inst(rp); | ||
445 | } | ||
446 | |||
432 | /* | 447 | /* |
433 | * Keep all fields in the kprobe consistent | 448 | * Keep all fields in the kprobe consistent |
434 | */ | 449 | */ |
@@ -798,7 +813,8 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p, | |||
798 | return 0; | 813 | return 0; |
799 | } | 814 | } |
800 | 815 | ||
801 | int __kprobes register_kretprobe(struct kretprobe *rp) | 816 | static int __kprobes __register_kretprobe(struct kretprobe *rp, |
817 | unsigned long called_from) | ||
802 | { | 818 | { |
803 | int ret = 0; | 819 | int ret = 0; |
804 | struct kretprobe_instance *inst; | 820 | struct kretprobe_instance *inst; |
@@ -844,43 +860,93 @@ int __kprobes register_kretprobe(struct kretprobe *rp) | |||
844 | 860 | ||
845 | rp->nmissed = 0; | 861 | rp->nmissed = 0; |
846 | /* Establish function entry probe point */ | 862 | /* Establish function entry probe point */ |
847 | if ((ret = __register_kprobe(&rp->kp, | 863 | ret = __register_kprobe(&rp->kp, called_from); |
848 | (unsigned long)__builtin_return_address(0))) != 0) | 864 | if (ret != 0) |
849 | free_rp_inst(rp); | 865 | free_rp_inst(rp); |
850 | return ret; | 866 | return ret; |
851 | } | 867 | } |
852 | 868 | ||
869 | static int __register_kretprobes(struct kretprobe **rps, int num, | ||
870 | unsigned long called_from) | ||
871 | { | ||
872 | int ret = 0, i; | ||
873 | |||
874 | if (num <= 0) | ||
875 | return -EINVAL; | ||
876 | for (i = 0; i < num; i++) { | ||
877 | ret = __register_kretprobe(rps[i], called_from); | ||
878 | if (ret < 0 && i > 0) { | ||
879 | unregister_kretprobes(rps, i); | ||
880 | break; | ||
881 | } | ||
882 | } | ||
883 | return ret; | ||
884 | } | ||
885 | |||
886 | int __kprobes register_kretprobe(struct kretprobe *rp) | ||
887 | { | ||
888 | return __register_kretprobes(&rp, 1, | ||
889 | (unsigned long)__builtin_return_address(0)); | ||
890 | } | ||
891 | |||
892 | void __kprobes unregister_kretprobe(struct kretprobe *rp) | ||
893 | { | ||
894 | unregister_kretprobes(&rp, 1); | ||
895 | } | ||
896 | |||
897 | int __kprobes register_kretprobes(struct kretprobe **rps, int num) | ||
898 | { | ||
899 | return __register_kretprobes(rps, num, | ||
900 | (unsigned long)__builtin_return_address(0)); | ||
901 | } | ||
902 | |||
903 | void __kprobes unregister_kretprobes(struct kretprobe **rps, int num) | ||
904 | { | ||
905 | int i; | ||
906 | |||
907 | if (num <= 0) | ||
908 | return; | ||
909 | mutex_lock(&kprobe_mutex); | ||
910 | for (i = 0; i < num; i++) | ||
911 | if (__unregister_kprobe_top(&rps[i]->kp) < 0) | ||
912 | rps[i]->kp.addr = NULL; | ||
913 | mutex_unlock(&kprobe_mutex); | ||
914 | |||
915 | synchronize_sched(); | ||
916 | for (i = 0; i < num; i++) { | ||
917 | if (rps[i]->kp.addr) { | ||
918 | __unregister_kprobe_bottom(&rps[i]->kp); | ||
919 | cleanup_rp_inst(rps[i]); | ||
920 | } | ||
921 | } | ||
922 | } | ||
923 | |||
853 | #else /* CONFIG_KRETPROBES */ | 924 | #else /* CONFIG_KRETPROBES */ |
854 | int __kprobes register_kretprobe(struct kretprobe *rp) | 925 | int __kprobes register_kretprobe(struct kretprobe *rp) |
855 | { | 926 | { |
856 | return -ENOSYS; | 927 | return -ENOSYS; |
857 | } | 928 | } |
858 | 929 | ||
859 | static int __kprobes pre_handler_kretprobe(struct kprobe *p, | 930 | int __kprobes register_kretprobes(struct kretprobe **rps, int num) |
860 | struct pt_regs *regs) | ||
861 | { | 931 | { |
862 | return 0; | 932 | return -ENOSYS; |
863 | } | 933 | } |
864 | #endif /* CONFIG_KRETPROBES */ | ||
865 | |||
866 | void __kprobes unregister_kretprobe(struct kretprobe *rp) | 934 | void __kprobes unregister_kretprobe(struct kretprobe *rp) |
867 | { | 935 | { |
868 | unsigned long flags; | 936 | } |
869 | struct kretprobe_instance *ri; | ||
870 | struct hlist_node *pos, *next; | ||
871 | 937 | ||
872 | unregister_kprobe(&rp->kp); | 938 | void __kprobes unregister_kretprobes(struct kretprobe **rps, int num) |
939 | { | ||
940 | } | ||
873 | 941 | ||
874 | /* No race here */ | 942 | static int __kprobes pre_handler_kretprobe(struct kprobe *p, |
875 | spin_lock_irqsave(&kretprobe_lock, flags); | 943 | struct pt_regs *regs) |
876 | hlist_for_each_entry_safe(ri, pos, next, &rp->used_instances, uflist) { | 944 | { |
877 | ri->rp = NULL; | 945 | return 0; |
878 | hlist_del(&ri->uflist); | ||
879 | } | ||
880 | spin_unlock_irqrestore(&kretprobe_lock, flags); | ||
881 | free_rp_inst(rp); | ||
882 | } | 946 | } |
883 | 947 | ||
948 | #endif /* CONFIG_KRETPROBES */ | ||
949 | |||
884 | static int __init init_kprobes(void) | 950 | static int __init init_kprobes(void) |
885 | { | 951 | { |
886 | int i, err = 0; | 952 | int i, err = 0; |
@@ -1177,4 +1243,6 @@ EXPORT_SYMBOL_GPL(jprobe_return); | |||
1177 | #ifdef CONFIG_KPROBES | 1243 | #ifdef CONFIG_KPROBES |
1178 | EXPORT_SYMBOL_GPL(register_kretprobe); | 1244 | EXPORT_SYMBOL_GPL(register_kretprobe); |
1179 | EXPORT_SYMBOL_GPL(unregister_kretprobe); | 1245 | EXPORT_SYMBOL_GPL(unregister_kretprobe); |
1246 | EXPORT_SYMBOL_GPL(register_kretprobes); | ||
1247 | EXPORT_SYMBOL_GPL(unregister_kretprobes); | ||
1180 | #endif | 1248 | #endif |