aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kprobes.c
diff options
context:
space:
mode:
authorAnanth N Mavinakayanahalli <ananth@in.ibm.com>2009-09-15 01:13:07 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2009-09-16 22:24:57 -0400
commit1f0ab40976460bc4673fa204ce917a725185d8f2 (patch)
treed854f402352917359729eb35e73bc34ee227c875 /kernel/kprobes.c
parent5a0d9050db4d1147722b42afef9011251b2651ee (diff)
kprobes: Prevent re-registration of the same kprobe
Prevent re-registration of the same kprobe. This situation, though unlikely, needs to be flagged since it can lead to a system crash if it's not handled. The core change itself is small, but the helper routine needed to be moved around a bit; hence the diffstat. Signed-off-by: Ananth N Mavinakayanahalli<ananth@in.ibm.com> Acked-by: Masami Hiramatsu <mhiramat@redhat.com> Cc: Jim Keniston <jkenisto@us.ibm.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: Frank Ch. Eigler <fche@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Jason Baron <jbaron@redhat.com> Cc: K.Prasad <prasad@linux.vnet.ibm.com> Cc: Lai Jiangshan <laijs@cn.fujitsu.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <20090915051307.GB26458@in.ibm.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Diffstat (limited to 'kernel/kprobes.c')
-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 */