]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
kprobes: Support __kprobes blacklist in modules
authorMasami Hiramatsu <mhiramat@kernel.org>
Thu, 26 Mar 2020 14:49:48 +0000 (23:49 +0900)
committerThomas Gleixner <tglx@linutronix.de>
Tue, 12 May 2020 15:15:32 +0000 (17:15 +0200)
Support __kprobes attribute for blacklist functions in modules.  The
__kprobes attribute functions are stored in .kprobes.text section.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Alexandre Chartre <alexandre.chartre@oracle.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20200505134059.678201813@linutronix.de
include/linux/module.h
kernel/kprobes.c
kernel/module.c

index 1ad393e62bef6d1e32016fa9a7bc3a2a669e68c9..369c354f9207d96d9c687313df2be4e560777a8b 100644 (file)
@@ -489,6 +489,10 @@ struct module {
        unsigned int num_ftrace_callsites;
        unsigned long *ftrace_callsites;
 #endif
+#ifdef CONFIG_KPROBES
+       void *kprobes_text_start;
+       unsigned int kprobes_text_size;
+#endif
 
 #ifdef CONFIG_LIVEPATCH
        bool klp; /* Is this a livepatch module? */
index 570d608276560f12e31e8f2392d73a0093b922b4..b7549992b9bdb565d2e52e902f8fd750227e87d6 100644 (file)
@@ -2179,6 +2179,19 @@ int kprobe_add_area_blacklist(unsigned long start, unsigned long end)
        return 0;
 }
 
+/* Remove all symbols in given area from kprobe blacklist */
+static void kprobe_remove_area_blacklist(unsigned long start, unsigned long end)
+{
+       struct kprobe_blacklist_entry *ent, *n;
+
+       list_for_each_entry_safe(ent, n, &kprobe_blacklist, list) {
+               if (ent->start_addr < start || ent->start_addr >= end)
+                       continue;
+               list_del(&ent->list);
+               kfree(ent);
+       }
+}
+
 int __init __weak arch_populate_kprobe_blacklist(void)
 {
        return 0;
@@ -2215,6 +2228,28 @@ static int __init populate_kprobe_blacklist(unsigned long *start,
        return ret ? : arch_populate_kprobe_blacklist();
 }
 
+static void add_module_kprobe_blacklist(struct module *mod)
+{
+       unsigned long start, end;
+
+       start = (unsigned long)mod->kprobes_text_start;
+       if (start) {
+               end = start + mod->kprobes_text_size;
+               kprobe_add_area_blacklist(start, end);
+       }
+}
+
+static void remove_module_kprobe_blacklist(struct module *mod)
+{
+       unsigned long start, end;
+
+       start = (unsigned long)mod->kprobes_text_start;
+       if (start) {
+               end = start + mod->kprobes_text_size;
+               kprobe_remove_area_blacklist(start, end);
+       }
+}
+
 /* Module notifier call back, checking kprobes on the module */
 static int kprobes_module_callback(struct notifier_block *nb,
                                   unsigned long val, void *data)
@@ -2225,6 +2260,11 @@ static int kprobes_module_callback(struct notifier_block *nb,
        unsigned int i;
        int checkcore = (val == MODULE_STATE_GOING);
 
+       if (val == MODULE_STATE_COMING) {
+               mutex_lock(&kprobe_mutex);
+               add_module_kprobe_blacklist(mod);
+               mutex_unlock(&kprobe_mutex);
+       }
        if (val != MODULE_STATE_GOING && val != MODULE_STATE_LIVE)
                return NOTIFY_DONE;
 
@@ -2255,6 +2295,8 @@ static int kprobes_module_callback(struct notifier_block *nb,
                                kill_kprobe(p);
                        }
        }
+       if (val == MODULE_STATE_GOING)
+               remove_module_kprobe_blacklist(mod);
        mutex_unlock(&kprobe_mutex);
        return NOTIFY_DONE;
 }
index 646f1e2330d2bdd9e3e82f62faff410d7d8ff37e..978f3fa4085082358825c90993c38846a570d33f 100644 (file)
@@ -3193,6 +3193,10 @@ static int find_module_sections(struct module *mod, struct load_info *info)
        mod->ei_funcs = section_objs(info, "_error_injection_whitelist",
                                            sizeof(*mod->ei_funcs),
                                            &mod->num_ei_funcs);
+#endif
+#ifdef CONFIG_KPROBES
+       mod->kprobes_text_start = section_objs(info, ".kprobes.text", 1,
+                                               &mod->kprobes_text_size);
 #endif
        mod->extable = section_objs(info, "__ex_table",
                                    sizeof(*mod->extable), &mod->num_exentries);