|
@@ -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
|