]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/kprobes.c
h63xx: tsc2101 alsa sound support
[linux-2.6-omap-h63xx.git] / kernel / kprobes.c
index f24cbab558f13e63d34ba6de7ba1bad728dbac50..fef1af8a73ce07818862eb434c29b62468e99323 100644 (file)
@@ -344,23 +344,6 @@ void __kprobes kprobe_flush_task(struct task_struct *tk)
        spin_unlock_irqrestore(&kretprobe_lock, flags);
 }
 
-/*
- * This kprobe pre_handler is registered with every kretprobe. When probe
- * hits it will set up the return probe.
- */
-static int __kprobes pre_handler_kretprobe(struct kprobe *p,
-                                          struct pt_regs *regs)
-{
-       struct kretprobe *rp = container_of(p, struct kretprobe, kp);
-       unsigned long flags = 0;
-
-       /*TODO: consider to only swap the RA after the last pre_handler fired */
-       spin_lock_irqsave(&kretprobe_lock, flags);
-       arch_prepare_kretprobe(rp, regs);
-       spin_unlock_irqrestore(&kretprobe_lock, flags);
-       return 0;
-}
-
 static inline void free_rp_inst(struct kretprobe *rp)
 {
        struct kretprobe_instance *ri;
@@ -431,7 +414,7 @@ static int __kprobes register_aggr_kprobe(struct kprobe *old_p,
                copy_kprobe(old_p, p);
                ret = add_new_kprobe(old_p, p);
        } else {
-               ap = kcalloc(1, sizeof(struct kprobe), GFP_KERNEL);
+               ap = kzalloc(sizeof(struct kprobe), GFP_KERNEL);
                if (!ap)
                        return -ENOMEM;
                add_aggr_kprobe(ap, old_p);
@@ -449,19 +432,32 @@ static int __kprobes in_kprobes_functions(unsigned long addr)
        return 0;
 }
 
-int __kprobes register_kprobe(struct kprobe *p)
+static int __kprobes __register_kprobe(struct kprobe *p,
+       unsigned long called_from)
 {
        int ret = 0;
        struct kprobe *old_p;
-       struct module *mod;
+       struct module *probed_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;
+       p->mod_refcounted = 0;
+       /* Check are we probing a module */
+       if ((probed_mod = module_text_address((unsigned long) p->addr))) {
+               struct module *calling_mod = module_text_address(called_from);
+               /* We must allow modules to probe themself and
+                * in this case avoid incrementing the module refcount,
+                * so as to allow unloading of self probing modules.
+                */
+               if (calling_mod && (calling_mod != probed_mod)) {
+                       if (unlikely(!try_module_get(probed_mod)))
+                               return -EINVAL;
+                       p->mod_refcounted = 1;
+               } else
+                       probed_mod = NULL;
+       }
 
        p->nmissed = 0;
        down(&kprobe_mutex);
@@ -483,11 +479,17 @@ int __kprobes register_kprobe(struct kprobe *p)
 out:
        up(&kprobe_mutex);
 
-       if (ret && mod)
-               module_put(mod);
+       if (ret && probed_mod)
+               module_put(probed_mod);
        return ret;
 }
 
+int __kprobes register_kprobe(struct kprobe *p)
+{
+       return __register_kprobe(p,
+               (unsigned long)__builtin_return_address(0));
+}
+
 void __kprobes unregister_kprobe(struct kprobe *p)
 {
        struct module *mod;
@@ -524,7 +526,8 @@ valid_p:
        up(&kprobe_mutex);
 
        synchronize_sched();
-       if ((mod = module_text_address((unsigned long)p->addr)))
+       if (p->mod_refcounted &&
+           (mod = module_text_address((unsigned long)p->addr)))
                module_put(mod);
 
        if (cleanup_p) {
@@ -547,7 +550,8 @@ int __kprobes register_jprobe(struct jprobe *jp)
        jp->kp.pre_handler = setjmp_pre_handler;
        jp->kp.break_handler = longjmp_break_handler;
 
-       return register_kprobe(&jp->kp);
+       return __register_kprobe(&jp->kp,
+               (unsigned long)__builtin_return_address(0));
 }
 
 void __kprobes unregister_jprobe(struct jprobe *jp)
@@ -557,6 +561,23 @@ void __kprobes unregister_jprobe(struct jprobe *jp)
 
 #ifdef ARCH_SUPPORTS_KRETPROBES
 
+/*
+ * This kprobe pre_handler is registered with every kretprobe. When probe
+ * hits it will set up the return probe.
+ */
+static int __kprobes pre_handler_kretprobe(struct kprobe *p,
+                                          struct pt_regs *regs)
+{
+       struct kretprobe *rp = container_of(p, struct kretprobe, kp);
+       unsigned long flags = 0;
+
+       /*TODO: consider to only swap the RA after the last pre_handler fired */
+       spin_lock_irqsave(&kretprobe_lock, flags);
+       arch_prepare_kretprobe(rp, regs);
+       spin_unlock_irqrestore(&kretprobe_lock, flags);
+       return 0;
+}
+
 int __kprobes register_kretprobe(struct kretprobe *rp)
 {
        int ret = 0;
@@ -587,7 +608,8 @@ int __kprobes register_kretprobe(struct kretprobe *rp)
 
        rp->nmissed = 0;
        /* Establish function entry probe point */
-       if ((ret = register_kprobe(&rp->kp)) != 0)
+       if ((ret = __register_kprobe(&rp->kp,
+               (unsigned long)__builtin_return_address(0))) != 0)
                free_rp_inst(rp);
        return ret;
 }
@@ -609,12 +631,12 @@ void __kprobes unregister_kretprobe(struct kretprobe *rp)
        unregister_kprobe(&rp->kp);
        /* No race here */
        spin_lock_irqsave(&kretprobe_lock, flags);
-       free_rp_inst(rp);
        while ((ri = get_used_rp_inst(rp)) != NULL) {
                ri->rp = NULL;
                hlist_del(&ri->uflist);
        }
        spin_unlock_irqrestore(&kretprobe_lock, flags);
+       free_rp_inst(rp);
 }
 
 static int __init init_kprobes(void)