]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - init/main.c
init/main.c: add initcall_blacklist kernel parameter
[karo-tx-linux.git] / init / main.c
index 9d3a7b84de5cac5adcab2aa53af4e054207e4024..8ac3833f2bdf62552030757de13916e9bc6d1011 100644 (file)
@@ -77,6 +77,7 @@
 #include <linux/sched_clock.h>
 #include <linux/context_tracking.h>
 #include <linux/random.h>
+#include <linux/list.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -665,6 +666,70 @@ static void __init do_ctors(void)
 bool initcall_debug;
 core_param(initcall_debug, initcall_debug, bool, 0644);
 
+#ifdef CONFIG_KALLSYMS
+struct blacklist_entry {
+       struct list_head next;
+       char *buf;
+};
+
+static __initdata_or_module LIST_HEAD(blacklisted_initcalls);
+
+static int __init initcall_blacklist(char *str)
+{
+       char *str_entry;
+       struct blacklist_entry *entry;
+
+       /* str argument is a comma-separated list of functions */
+       do {
+               str_entry = strsep(&str, ",");
+               if (str_entry) {
+                       pr_debug("blacklisting initcall %s\n", str_entry);
+                       entry = alloc_bootmem(sizeof(*entry));
+                       entry->buf = alloc_bootmem(strlen(str_entry) + 1);
+                       strcpy(entry->buf, str_entry);
+                       list_add(&entry->next, &blacklisted_initcalls);
+               }
+       } while (str_entry);
+
+       return 0;
+}
+
+static bool __init_or_module initcall_blacklisted(initcall_t fn)
+{
+       struct list_head *tmp;
+       struct blacklist_entry *entry;
+       char *fn_name;
+
+       fn_name = kasprintf(GFP_KERNEL, "%pf", fn);
+       if (!fn_name)
+               return false;
+
+       list_for_each(tmp, &blacklisted_initcalls) {
+               entry = list_entry(tmp, struct blacklist_entry, next);
+               if (!strcmp(fn_name, entry->buf)) {
+                       pr_debug("initcall %s blacklisted\n", fn_name);
+                       kfree(fn_name);
+                       return true;
+               }
+       }
+
+       kfree(fn_name);
+       return false;
+}
+#else
+static int __init initcall_blacklist(char *str)
+{
+       pr_warn("initcall_blacklist requires CONFIG_KALLSYMS\n");
+       return 0;
+}
+
+static bool __init_or_module initcall_blacklisted(initcall_t fn)
+{
+       return false;
+}
+#endif
+__setup("initcall_blacklist=", initcall_blacklist);
+
 static int __init_or_module do_one_initcall_debug(initcall_t fn)
 {
        ktime_t calltime, delta, rettime;
@@ -689,6 +754,9 @@ int __init_or_module do_one_initcall(initcall_t fn)
        int ret;
        char msgbuf[64];
 
+       if (initcall_blacklisted(fn))
+               return -EPERM;
+
        if (initcall_debug)
                ret = do_one_initcall_debug(fn);
        else