aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/kprobes.c58
1 files changed, 38 insertions, 20 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 00d01b0f9fee..b946761f84bd 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -676,6 +676,40 @@ static kprobe_opcode_t __kprobes *kprobe_addr(struct kprobe *p)
676 return (kprobe_opcode_t *)(((char *)addr) + p->offset); 676 return (kprobe_opcode_t *)(((char *)addr) + p->offset);
677} 677}
678 678
679/* Check passed kprobe is valid and return kprobe in kprobe_table. */
680static 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 }
695valid:
696 return old_p;
697}
698
699/* Return error if the kprobe is being re-registered */
700static 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
679int __kprobes register_kprobe(struct kprobe *p) 713int __kprobes register_kprobe(struct kprobe *p)
680{ 714{
681 int ret = 0; 715 int ret = 0;
@@ -688,6 +722,10 @@ int __kprobes register_kprobe(struct kprobe *p)
688 return -EINVAL; 722 return -EINVAL;
689 p->addr = addr; 723 p->addr = addr;
690 724
725 ret = check_kprobe_rereg(p);
726 if (ret)
727 return ret;
728
691 preempt_disable(); 729 preempt_disable();
692 if (!kernel_text_address((unsigned long) p->addr) || 730 if (!kernel_text_address((unsigned long) p->addr) ||
693 in_kprobes_functions((unsigned long) p->addr)) { 731 in_kprobes_functions((unsigned long) p->addr)) {
@@ -757,26 +795,6 @@ out:
757} 795}
758EXPORT_SYMBOL_GPL(register_kprobe); 796EXPORT_SYMBOL_GPL(register_kprobe);
759 797
760/* Check passed kprobe is valid and return kprobe in kprobe_table. */
761static struct kprobe * __kprobes __get_valid_kprobe(struct kprobe *p)
762{
763 struct kprobe *old_p, *list_p;
764
765 old_p = get_kprobe(p->addr);
766 if (unlikely(!old_p))
767 return NULL;
768
769 if (p != old_p) {
770 list_for_each_entry_rcu(list_p, &old_p->list, list)
771 if (list_p == p)
772 /* kprobe p is a valid probe */
773 goto valid;
774 return NULL;
775 }
776valid:
777 return old_p;
778}
779
780/* 798/*
781 * Unregister a kprobe without a scheduler synchronization. 799 * Unregister a kprobe without a scheduler synchronization.
782 */ 800 */