kprobes: cleanup to separate probe-able check
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Tue, 5 Jun 2012 10:28:20 +0000 (19:28 +0900)
committerSteven Rostedt <rostedt@goodmis.org>
Tue, 31 Jul 2012 14:29:56 +0000 (10:29 -0400)
Separate probe-able address checking code from
register_kprobe().

Link: http://lkml.kernel.org/r/20120605102820.27845.90133.stgit@localhost.localdomain
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: "Frank Ch. Eigler" <fche@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
kernel/kprobes.c

index 7a8a122..6137fe3 100644 (file)
@@ -1313,67 +1313,80 @@ static inline int check_kprobe_rereg(struct kprobe *p)
        return ret;
 }
 
-int __kprobes register_kprobe(struct kprobe *p)
+static __kprobes int check_kprobe_address_safe(struct kprobe *p,
+                                              struct module **probed_mod)
 {
        int ret = 0;
-       struct kprobe *old_p;
-       struct module *probed_mod;
-       kprobe_opcode_t *addr;
-
-       addr = kprobe_addr(p);
-       if (IS_ERR(addr))
-               return PTR_ERR(addr);
-       p->addr = addr;
-
-       ret = check_kprobe_rereg(p);
-       if (ret)
-               return ret;
 
        jump_label_lock();
        preempt_disable();
+
+       /* Ensure it is not in reserved area nor out of text */
        if (!kernel_text_address((unsigned long) p->addr) ||
            in_kprobes_functions((unsigned long) p->addr) ||
            ftrace_text_reserved(p->addr, p->addr) ||
            jump_label_text_reserved(p->addr, p->addr)) {
                ret = -EINVAL;
-               goto cannot_probe;
+               goto out;
        }
 
-       /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */
-       p->flags &= KPROBE_FLAG_DISABLED;
-
-       /*
-        * Check if are we probing a module.
-        */
-       probed_mod = __module_text_address((unsigned long) p->addr);
-       if (probed_mod) {
-               /* Return -ENOENT if fail. */
-               ret = -ENOENT;
+       /* Check if are we probing a module */
+       *probed_mod = __module_text_address((unsigned long) p->addr);
+       if (*probed_mod) {
                /*
                 * We must hold a refcount of the probed module while updating
                 * its code to prohibit unexpected unloading.
                 */
-               if (unlikely(!try_module_get(probed_mod)))
-                       goto cannot_probe;
+               if (unlikely(!try_module_get(*probed_mod))) {
+                       ret = -ENOENT;
+                       goto out;
+               }
 
                /*
                 * If the module freed .init.text, we couldn't insert
                 * kprobes in there.
                 */
-               if (within_module_init((unsigned long)p->addr, probed_mod) &&
-                   probed_mod->state != MODULE_STATE_COMING) {
-                       module_put(probed_mod);
-                       goto cannot_probe;
+               if (within_module_init((unsigned long)p->addr, *probed_mod) &&
+                   (*probed_mod)->state != MODULE_STATE_COMING) {
+                       module_put(*probed_mod);
+                       *probed_mod = NULL;
+                       ret = -ENOENT;
                }
-               /* ret will be updated by following code */
        }
+out:
        preempt_enable();
        jump_label_unlock();
 
+       return ret;
+}
+
+int __kprobes register_kprobe(struct kprobe *p)
+{
+       int ret;
+       struct kprobe *old_p;
+       struct module *probed_mod;
+       kprobe_opcode_t *addr;
+
+       /* Adjust probe address from symbol */
+       addr = kprobe_addr(p);
+       if (IS_ERR(addr))
+               return PTR_ERR(addr);
+       p->addr = addr;
+
+       ret = check_kprobe_rereg(p);
+       if (ret)
+               return ret;
+
+       /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */
+       p->flags &= KPROBE_FLAG_DISABLED;
        p->nmissed = 0;
        INIT_LIST_HEAD(&p->list);
-       mutex_lock(&kprobe_mutex);
 
+       ret = check_kprobe_address_safe(p, &probed_mod);
+       if (ret)
+               return ret;
+
+       mutex_lock(&kprobe_mutex);
        jump_label_lock(); /* needed to call jump_label_text_reserved() */
 
        get_online_cpus();      /* For avoiding text_mutex deadlock. */
@@ -1410,11 +1423,6 @@ out:
                module_put(probed_mod);
 
        return ret;
-
-cannot_probe:
-       preempt_enable();
-       jump_label_unlock();
-       return ret;
 }
 EXPORT_SYMBOL_GPL(register_kprobe);