bpf: enable access to ax register also from verifier rewrite
[linux-2.6-microblaze.git] / kernel / kprobes.c
index 90e98e2..f4ddfdd 100644 (file)
@@ -229,7 +229,7 @@ static int collect_garbage_slots(struct kprobe_insn_cache *c)
        struct kprobe_insn_page *kip, *next;
 
        /* Ensure no-one is interrupted on the garbages */
-       synchronize_sched();
+       synchronize_rcu();
 
        list_for_each_entry_safe(kip, next, &c->pages, list) {
                int i;
@@ -1382,7 +1382,7 @@ out:
                        if (ret) {
                                ap->flags |= KPROBE_FLAG_DISABLED;
                                list_del_rcu(&p->list);
-                               synchronize_sched();
+                               synchronize_rcu();
                        }
                }
        }
@@ -1597,7 +1597,7 @@ int register_kprobe(struct kprobe *p)
                ret = arm_kprobe(p);
                if (ret) {
                        hlist_del_rcu(&p->hlist);
-                       synchronize_sched();
+                       synchronize_rcu();
                        goto out;
                }
        }
@@ -1776,7 +1776,7 @@ void unregister_kprobes(struct kprobe **kps, int num)
                        kps[i]->addr = NULL;
        mutex_unlock(&kprobe_mutex);
 
-       synchronize_sched();
+       synchronize_rcu();
        for (i = 0; i < num; i++)
                if (kps[i]->addr)
                        __unregister_kprobe_bottom(kps[i]);
@@ -1966,7 +1966,7 @@ void unregister_kretprobes(struct kretprobe **rps, int num)
                        rps[i]->kp.addr = NULL;
        mutex_unlock(&kprobe_mutex);
 
-       synchronize_sched();
+       synchronize_rcu();
        for (i = 0; i < num; i++) {
                if (rps[i]->kp.addr) {
                        __unregister_kprobe_bottom(&rps[i]->kp);
@@ -2093,6 +2093,47 @@ void dump_kprobe(struct kprobe *kp)
 }
 NOKPROBE_SYMBOL(dump_kprobe);
 
+int kprobe_add_ksym_blacklist(unsigned long entry)
+{
+       struct kprobe_blacklist_entry *ent;
+       unsigned long offset = 0, size = 0;
+
+       if (!kernel_text_address(entry) ||
+           !kallsyms_lookup_size_offset(entry, &size, &offset))
+               return -EINVAL;
+
+       ent = kmalloc(sizeof(*ent), GFP_KERNEL);
+       if (!ent)
+               return -ENOMEM;
+       ent->start_addr = entry;
+       ent->end_addr = entry + size;
+       INIT_LIST_HEAD(&ent->list);
+       list_add_tail(&ent->list, &kprobe_blacklist);
+
+       return (int)size;
+}
+
+/* Add all symbols in given area into kprobe blacklist */
+int kprobe_add_area_blacklist(unsigned long start, unsigned long end)
+{
+       unsigned long entry;
+       int ret = 0;
+
+       for (entry = start; entry < end; entry += ret) {
+               ret = kprobe_add_ksym_blacklist(entry);
+               if (ret < 0)
+                       return ret;
+               if (ret == 0)   /* In case of alias symbol */
+                       ret = 1;
+       }
+       return 0;
+}
+
+int __init __weak arch_populate_kprobe_blacklist(void)
+{
+       return 0;
+}
+
 /*
  * Lookup and populate the kprobe_blacklist.
  *
@@ -2104,26 +2145,24 @@ NOKPROBE_SYMBOL(dump_kprobe);
 static int __init populate_kprobe_blacklist(unsigned long *start,
                                             unsigned long *end)
 {
+       unsigned long entry;
        unsigned long *iter;
-       struct kprobe_blacklist_entry *ent;
-       unsigned long entry, offset = 0, size = 0;
+       int ret;
 
        for (iter = start; iter < end; iter++) {
                entry = arch_deref_entry_point((void *)*iter);
-
-               if (!kernel_text_address(entry) ||
-                   !kallsyms_lookup_size_offset(entry, &size, &offset))
+               ret = kprobe_add_ksym_blacklist(entry);
+               if (ret == -EINVAL)
                        continue;
-
-               ent = kmalloc(sizeof(*ent), GFP_KERNEL);
-               if (!ent)
-                       return -ENOMEM;
-               ent->start_addr = entry;
-               ent->end_addr = entry + size;
-               INIT_LIST_HEAD(&ent->list);
-               list_add_tail(&ent->list, &kprobe_blacklist);
+               if (ret < 0)
+                       return ret;
        }
-       return 0;
+
+       /* Symbols in __kprobes_text are blacklisted */
+       ret = kprobe_add_area_blacklist((unsigned long)__kprobes_text_start,
+                                       (unsigned long)__kprobes_text_end);
+
+       return ret ? : arch_populate_kprobe_blacklist();
 }
 
 /* Module notifier call back, checking kprobes on the module */