]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/kprobes.c
kprobes: check CONFIG_FREEZER instead of CONFIG_PM
[linux-2.6-omap-h63xx.git] / kernel / kprobes.c
index cb732a9aa55f6ffee607dac8e51de523872398b1..7ba8cd9845cbe90aee7b1c54711633ad827e24ca 100644 (file)
@@ -123,7 +123,7 @@ static int collect_garbage_slots(void);
 static int __kprobes check_safety(void)
 {
        int ret = 0;
-#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_FREEZER)
        ret = freeze_processes();
        if (ret == 0) {
                struct task_struct *p, *q;
@@ -644,8 +644,7 @@ static kprobe_opcode_t __kprobes *kprobe_addr(struct kprobe *p)
        return (kprobe_opcode_t *)(((char *)addr) + p->offset);
 }
 
-static int __kprobes __register_kprobe(struct kprobe *p,
-       unsigned long called_from)
+int __kprobes register_kprobe(struct kprobe *p)
 {
        int ret = 0;
        struct kprobe *old_p;
@@ -670,19 +669,24 @@ static int __kprobes __register_kprobe(struct kprobe *p,
         */
        probed_mod = __module_text_address((unsigned long) p->addr);
        if (probed_mod) {
-               struct module *calling_mod;
-               calling_mod = __module_text_address(called_from);
                /*
                 * We must hold a refcount of the probed module while updating
                 * its code to prohibit unexpected unloading.
                 */
-               if (calling_mod != probed_mod) {
-                       if (unlikely(!try_module_get(probed_mod))) {
-                               preempt_enable();
-                               return -EINVAL;
-                       }
-               } else
-                       probed_mod = NULL;
+               if (unlikely(!try_module_get(probed_mod))) {
+                       preempt_enable();
+                       return -EINVAL;
+               }
+               /*
+                * 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);
+                       preempt_enable();
+                       return -EINVAL;
+               }
        }
        preempt_enable();
 
@@ -776,15 +780,14 @@ static void __kprobes __unregister_kprobe_bottom(struct kprobe *p)
        }
 }
 
-static int __kprobes __register_kprobes(struct kprobe **kps, int num,
-       unsigned long called_from)
+int __kprobes register_kprobes(struct kprobe **kps, int num)
 {
        int i, ret = 0;
 
        if (num <= 0)
                return -EINVAL;
        for (i = 0; i < num; i++) {
-               ret = __register_kprobe(kps[i], called_from);
+               ret = register_kprobe(kps[i]);
                if (ret < 0) {
                        if (i > 0)
                                unregister_kprobes(kps, i);
@@ -794,26 +797,11 @@ static int __kprobes __register_kprobes(struct kprobe **kps, int num,
        return ret;
 }
 
-/*
- * Registration and unregistration functions for kprobe.
- */
-int __kprobes register_kprobe(struct kprobe *p)
-{
-       return __register_kprobes(&p, 1,
-                                 (unsigned long)__builtin_return_address(0));
-}
-
 void __kprobes unregister_kprobe(struct kprobe *p)
 {
        unregister_kprobes(&p, 1);
 }
 
-int __kprobes register_kprobes(struct kprobe **kps, int num)
-{
-       return __register_kprobes(kps, num,
-                                 (unsigned long)__builtin_return_address(0));
-}
-
 void __kprobes unregister_kprobes(struct kprobe **kps, int num)
 {
        int i;
@@ -842,8 +830,7 @@ unsigned long __weak arch_deref_entry_point(void *entry)
        return (unsigned long)entry;
 }
 
-static int __kprobes __register_jprobes(struct jprobe **jps, int num,
-       unsigned long called_from)
+int __kprobes register_jprobes(struct jprobe **jps, int num)
 {
        struct jprobe *jp;
        int ret = 0, i;
@@ -861,7 +848,7 @@ static int __kprobes __register_jprobes(struct jprobe **jps, int num,
                        /* Todo: Verify probepoint is a function entry point */
                        jp->kp.pre_handler = setjmp_pre_handler;
                        jp->kp.break_handler = longjmp_break_handler;
-                       ret = __register_kprobe(&jp->kp, called_from);
+                       ret = register_kprobe(&jp->kp);
                }
                if (ret < 0) {
                        if (i > 0)
@@ -874,8 +861,7 @@ static int __kprobes __register_jprobes(struct jprobe **jps, int num,
 
 int __kprobes register_jprobe(struct jprobe *jp)
 {
-       return __register_jprobes(&jp, 1,
-               (unsigned long)__builtin_return_address(0));
+       return register_jprobes(&jp, 1);
 }
 
 void __kprobes unregister_jprobe(struct jprobe *jp)
@@ -883,12 +869,6 @@ void __kprobes unregister_jprobe(struct jprobe *jp)
        unregister_jprobes(&jp, 1);
 }
 
-int __kprobes register_jprobes(struct jprobe **jps, int num)
-{
-       return __register_jprobes(jps, num,
-               (unsigned long)__builtin_return_address(0));
-}
-
 void __kprobes unregister_jprobes(struct jprobe **jps, int num)
 {
        int i;
@@ -951,8 +931,7 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p,
        return 0;
 }
 
-static int __kprobes __register_kretprobe(struct kretprobe *rp,
-                                         unsigned long called_from)
+int __kprobes register_kretprobe(struct kretprobe *rp)
 {
        int ret = 0;
        struct kretprobe_instance *inst;
@@ -998,21 +977,20 @@ static int __kprobes __register_kretprobe(struct kretprobe *rp,
 
        rp->nmissed = 0;
        /* Establish function entry probe point */
-       ret = __register_kprobe(&rp->kp, called_from);
+       ret = register_kprobe(&rp->kp);
        if (ret != 0)
                free_rp_inst(rp);
        return ret;
 }
 
-static int __kprobes __register_kretprobes(struct kretprobe **rps, int num,
-       unsigned long called_from)
+int __kprobes register_kretprobes(struct kretprobe **rps, int num)
 {
        int ret = 0, i;
 
        if (num <= 0)
                return -EINVAL;
        for (i = 0; i < num; i++) {
-               ret = __register_kretprobe(rps[i], called_from);
+               ret = register_kretprobe(rps[i]);
                if (ret < 0) {
                        if (i > 0)
                                unregister_kretprobes(rps, i);
@@ -1022,23 +1000,11 @@ static int __kprobes __register_kretprobes(struct kretprobe **rps, int num,
        return ret;
 }
 
-int __kprobes register_kretprobe(struct kretprobe *rp)
-{
-       return __register_kretprobes(&rp, 1,
-                       (unsigned long)__builtin_return_address(0));
-}
-
 void __kprobes unregister_kretprobe(struct kretprobe *rp)
 {
        unregister_kretprobes(&rp, 1);
 }
 
-int __kprobes register_kretprobes(struct kretprobe **rps, int num)
-{
-       return __register_kretprobes(rps, num,
-                       (unsigned long)__builtin_return_address(0));
-}
-
 void __kprobes unregister_kretprobes(struct kretprobe **rps, int num)
 {
        int i;
@@ -1117,19 +1083,24 @@ static int __kprobes kprobes_module_callback(struct notifier_block *nb,
        struct hlist_node *node;
        struct kprobe *p;
        unsigned int i;
+       int checkcore = (val == MODULE_STATE_GOING);
 
-       if (val != MODULE_STATE_GOING)
+       if (val != MODULE_STATE_GOING && val != MODULE_STATE_LIVE)
                return NOTIFY_DONE;
 
        /*
-        * module .text section will be freed. We need to
-        * disable kprobes which have been inserted in the section.
+        * When MODULE_STATE_GOING was notified, both of module .text and
+        * .init.text sections would be freed. When MODULE_STATE_LIVE was
+        * notified, only .init.text section would be freed. We need to
+        * disable kprobes which have been inserted in the sections.
         */
        mutex_lock(&kprobe_mutex);
        for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
                head = &kprobe_table[i];
                hlist_for_each_entry_rcu(p, node, head, hlist)
-                       if (within_module_core((unsigned long)p->addr, mod)) {
+                       if (within_module_init((unsigned long)p->addr, mod) ||
+                           (checkcore &&
+                            within_module_core((unsigned long)p->addr, mod))) {
                                /*
                                 * The vaddr this probe is installed will soon
                                 * be vfreed buy not synced to disk. Hence,