Merge tag 'core-static_call-2020-10-12' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / kernel / kprobes.c
index 67e6a8c18007ab684c6b465951bf7a4ad2d9c888..c16c3236f6cfa962ea92c539e9935ab2735ebb97 100644 (file)
@@ -2142,6 +2142,9 @@ static void kill_kprobe(struct kprobe *p)
 
        lockdep_assert_held(&kprobe_mutex);
 
+       if (WARN_ON_ONCE(kprobe_gone(p)))
+               return;
+
        p->flags |= KPROBE_FLAG_GONE;
        if (kprobe_aggrprobe(p)) {
                /*
@@ -2161,9 +2164,10 @@ static void kill_kprobe(struct kprobe *p)
 
        /*
         * The module is going away. We should disarm the kprobe which
-        * is using ftrace.
+        * is using ftrace, because ftrace framework is still available at
+        * MODULE_STATE_GOING notification.
         */
-       if (kprobe_ftrace(p))
+       if (kprobe_ftrace(p) && !kprobe_disabled(p) && !kprobes_all_disarmed)
                disarm_kprobe_ftrace(p);
 }
 
@@ -2421,7 +2425,10 @@ static int kprobes_module_callback(struct notifier_block *nb,
        mutex_lock(&kprobe_mutex);
        for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
                head = &kprobe_table[i];
-               hlist_for_each_entry(p, head, hlist)
+               hlist_for_each_entry(p, head, hlist) {
+                       if (kprobe_gone(p))
+                               continue;
+
                        if (within_module_init((unsigned long)p->addr, mod) ||
                            (checkcore &&
                             within_module_core((unsigned long)p->addr, mod))) {
@@ -2438,6 +2445,7 @@ static int kprobes_module_callback(struct notifier_block *nb,
                                 */
                                kill_kprobe(p);
                        }
+               }
        }
        if (val == MODULE_STATE_GOING)
                remove_module_kprobe_blacklist(mod);
@@ -2454,6 +2462,28 @@ static struct notifier_block kprobe_module_nb = {
 extern unsigned long __start_kprobe_blacklist[];
 extern unsigned long __stop_kprobe_blacklist[];
 
+void kprobe_free_init_mem(void)
+{
+       void *start = (void *)(&__init_begin);
+       void *end = (void *)(&__init_end);
+       struct hlist_head *head;
+       struct kprobe *p;
+       int i;
+
+       mutex_lock(&kprobe_mutex);
+
+       /* Kill all kprobes on initmem */
+       for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
+               head = &kprobe_table[i];
+               hlist_for_each_entry(p, head, hlist) {
+                       if (start <= (void *)p->addr && (void *)p->addr < end)
+                               kill_kprobe(p);
+               }
+       }
+
+       mutex_unlock(&kprobe_mutex);
+}
+
 static int __init init_kprobes(void)
 {
        int i, err = 0;