]> err.no Git - linux-2.6/commitdiff
[PATCH] Kprobes: Reference count the modules when probed on it
authorMao, Bibo <bibo.mao@intel.com>
Mon, 12 Dec 2005 08:37:00 +0000 (00:37 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 12 Dec 2005 16:57:41 +0000 (08:57 -0800)
When a Kprobes are inserted/removed on a modules, the modules must be ref
counted so as not to allow to unload while probes are registered on that
module.

Without this patch, the probed module is free to unload, and when the
probing module unregister the probe, the kpobes code while trying to
replace the original instruction might crash.

Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Signed-off-by: Mao Bibo <bibo.mao@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
kernel/kprobes.c

index 5beda378cc7518b353dc5f0551c636d8dd81b02a..fde5a16a2913c2675d28c46e37f88b7cc28a82aa 100644 (file)
@@ -462,9 +462,16 @@ int __kprobes register_kprobe(struct kprobe *p)
        int ret = 0;
        unsigned long flags = 0;
        struct kprobe *old_p;
+       struct module *mod;
+
+       if ((!kernel_text_address((unsigned long) p->addr)) ||
+               in_kprobes_functions((unsigned long) p->addr))
+               return -EINVAL;
+
+       if ((mod = module_text_address((unsigned long) p->addr)) &&
+                       (unlikely(!try_module_get(mod))))
+               return -EINVAL;
 
-       if ((ret = in_kprobes_functions((unsigned long) p->addr)) != 0)
-               return ret;
        if ((ret = arch_prepare_kprobe(p)) != 0)
                goto rm_kprobe;
 
@@ -488,6 +495,8 @@ out:
 rm_kprobe:
        if (ret == -EEXIST)
                arch_remove_kprobe(p);
+       if (ret && mod)
+               module_put(mod);
        return ret;
 }
 
@@ -495,6 +504,7 @@ void __kprobes unregister_kprobe(struct kprobe *p)
 {
        unsigned long flags;
        struct kprobe *old_p;
+       struct module *mod;
 
        spin_lock_irqsave(&kprobe_lock, flags);
        old_p = get_kprobe(p->addr);
@@ -506,6 +516,10 @@ void __kprobes unregister_kprobe(struct kprobe *p)
                        cleanup_kprobe(p, flags);
 
                synchronize_sched();
+
+               if ((mod = module_text_address((unsigned long)p->addr)))
+                       module_put(mod);
+
                if (old_p->pre_handler == aggr_pre_handler &&
                                list_empty(&old_p->list))
                        kfree(old_p);