From: Aaron Tomlin <atomlin@atomlin.com>
To: arnd@arndb.de, mcgrof@kernel.org, petr.pavlu@suse.com,
da.gomez@kernel.org, samitolvanen@google.com,
peterz@infradead.org
Cc: mhiramat@kernel.org, atomlin@atomlin.com, neelx@suse.com,
da.anzani@gmail.com, sean@ashe.io, chjohnst@mail.com,
steve@abita.co, mproche@mail.com, nick.lane@mail.com,
linux-arch@vger.kernel.org, linux-modules@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH v2] module: Extend module_blacklist parameter to built-in modules
Date: Mon, 22 Jun 2026 10:02:59 -0400 [thread overview]
Message-ID: <20260622140259.2974-1-atomlin@atomlin.com> (raw)
Currently, the module_blacklist= parameter only prevents
the dynamic loading of external modules. It possesses no mechanism to
intercept or prevent the initialisation of built-in modules, as their
associated initcalls are invoked unconditionally during system boot.
This patch extends the blacklisting behaviour to encompass built-in
modules. It introduces a dedicated ".initcall.modnames" section into
the linker script, systematically mapping each initcall to its
originating module name. During the boot sequence, do_one_initcall()
interrogates this mapping; should the executing initcall belong to a
blacklisted module, its execution is explicitly bypassed.
Furthermore, to preserve the efficacy of Kernel Address Space Layout
Randomisation (KASLR) and prevent binary bloat, the mapping mechanism
rigorously adheres to CONFIG_HAVE_ARCH_PREL32_RELOCATIONS. Rather than
storing absolute function pointers, it employs 32-bit relative offsets,
successfully avoiding the generation of thousands of absolute
relocations.
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
--
Changes since v1:
- Pivoted entirely from exposing built-in initcalls and their blacklist
status via a debugfs interface to directly extending the existing
"module_blacklist=" to intercept built-in modules at boot (Petr Pavlu)
- Implemented 32-bit relative offsets (CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)
to store the mappings, preventing binary bloat and preserving KASLR
efficacy
- Linked to v1: https://lore.kernel.org/lkml/20260510061301.41341-1-atomlin@atomlin.com/
---
include/asm-generic/vmlinux.lds.h | 7 +++++++
include/linux/init.h | 31 +++++++++++++++++++++++++++++--
include/linux/module.h | 2 ++
init/main.c | 27 +++++++++++++++++++++++++++
kernel/module/main.c | 4 ++--
5 files changed, 67 insertions(+), 4 deletions(-)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 5659f4b5a125..ac0e5f4f2893 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -957,6 +957,12 @@
#define CON_INITCALL \
BOUNDED_SECTION_POST_LABEL(.con_initcall.init, __con_initcall, _start, _end)
+#define INITCALL_MODNAMES \
+ . = ALIGN(8); \
+ __start_initcall_modnames = .; \
+ KEEP(*(.initcall.modnames)) \
+ __stop_initcall_modnames = .;
+
#define NAMED_SECTION(name) \
. = ALIGN(8); \
name : AT(ADDR(name) - LOAD_OFFSET) \
@@ -1166,6 +1172,7 @@
INIT_SETUP(initsetup_align) \
INIT_CALLS \
CON_INITCALL \
+ INITCALL_MODNAMES \
INIT_RAM_FS \
}
diff --git a/include/linux/init.h b/include/linux/init.h
index 40331923b9f4..212f64a07c73 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -125,6 +125,16 @@ static inline initcall_t initcall_from_entry(initcall_entry_t *entry)
}
#endif
+struct initcall_modname {
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+ initcall_entry_t initcall_fn;
+ int modname_offset;
+#else
+ initcall_t initcall_fn;
+ const char *modname;
+#endif
+};
+
extern initcall_entry_t __con_initcall_start[], __con_initcall_end[];
/* Used for constructor calls. */
@@ -270,9 +280,26 @@ extern struct module __this_module;
__initcall_stub(fn, __iid, id), \
__initcall_name(initcall, __iid, id), \
__initcall_section(__sec, __iid))
-
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+#define ___define_initcall(fn, id, __sec) \
+ __unique_initcall(fn, id, __sec, __initcall_id(fn)); \
+ asm(".pushsection \".initcall.modnames\", \"a\"\n" \
+ ".balign 4\n" \
+ ".long " #fn " - .\n" \
+ ".long __initcall_modstr_" #fn #id " - .\n" \
+ ".popsection\n" \
+ ".pushsection .init.rodata, \"a\"\n" \
+ "__initcall_modstr_" #fn #id ": .string \"" KBUILD_MODNAME "\"\n" \
+ ".popsection\n");
+#else
#define ___define_initcall(fn, id, __sec) \
- __unique_initcall(fn, id, __sec, __initcall_id(fn))
+ __unique_initcall(fn, id, __sec, __initcall_id(fn)); \
+ static struct initcall_modname __initcall_modname_##fn##id __used \
+ __section(".initcall.modnames") = { \
+ .initcall_fn = fn, \
+ .modname = KBUILD_MODNAME \
+ };
+#endif
#define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
diff --git a/include/linux/module.h b/include/linux/module.h
index 7566815fabbe..7e25fcd61b50 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -756,6 +756,8 @@ void *dereference_module_function_descriptor(struct module *mod, void *ptr);
int register_module_notifier(struct notifier_block *nb);
int unregister_module_notifier(struct notifier_block *nb);
+extern bool module_is_blacklisted(const char *module_name);
+
extern void print_modules(void);
static inline bool module_requested_async_probing(struct module *module)
diff --git a/init/main.c b/init/main.c
index e363232b428b..fbdc42859791 100644
--- a/init/main.c
+++ b/init/main.c
@@ -1334,12 +1334,39 @@ static inline void do_trace_initcall_level(const char *level)
}
#endif /* !TRACEPOINTS_ENABLED */
+extern struct initcall_modname __start_initcall_modnames[];
+extern struct initcall_modname __stop_initcall_modnames[];
+
+static const char *initcall_get_modname(initcall_t fn)
+{
+ struct initcall_modname *p;
+
+ for (p = __start_initcall_modnames; p < __stop_initcall_modnames; p++) {
+ if (initcall_from_entry(&p->initcall_fn) == fn) {
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+ return (const char *)offset_to_ptr(&p->modname_offset);
+#else
+ return p->modname;
+#endif
+ }
+ }
+ return NULL;
+}
+
int __init_or_module do_one_initcall(initcall_t fn)
{
int count = preempt_count();
char msgbuf[64];
+ const char *modname;
int ret;
+ modname = initcall_get_modname(fn);
+ if (modname && module_is_blacklisted(modname)) {
+ pr_info("Skipping initcall for blacklisted built-in module %s\n",
+ modname);
+ return 0;
+ }
+
if (initcall_blacklisted(fn))
return -EPERM;
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 46dd8d25a605..02deee5a7480 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2921,7 +2921,7 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr,
/* module_blacklist is a comma-separated list of module names */
static char *module_blacklist;
-static bool blacklisted(const char *module_name)
+bool module_is_blacklisted(const char *module_name)
{
const char *p;
size_t len;
@@ -3391,7 +3391,7 @@ static int early_mod_check(struct load_info *info, int flags)
* Now that we know we have the correct module name, check
* if it's blacklisted.
*/
- if (blacklisted(info->name)) {
+ if (module_is_blacklisted(info->name)) {
pr_err("Module %s is blacklisted\n", info->name);
return -EPERM;
}
--
2.51.0
next reply other threads:[~2026-06-22 14:03 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-22 14:02 Aaron Tomlin [this message]
2026-06-22 14:17 ` [PATCH v2] module: Extend module_blacklist parameter to built-in modules sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260622140259.2974-1-atomlin@atomlin.com \
--to=atomlin@atomlin.com \
--cc=arnd@arndb.de \
--cc=chjohnst@mail.com \
--cc=da.anzani@gmail.com \
--cc=da.gomez@kernel.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-modules@vger.kernel.org \
--cc=mcgrof@kernel.org \
--cc=mhiramat@kernel.org \
--cc=mproche@mail.com \
--cc=neelx@suse.com \
--cc=nick.lane@mail.com \
--cc=peterz@infradead.org \
--cc=petr.pavlu@suse.com \
--cc=samitolvanen@google.com \
--cc=sean@ashe.io \
--cc=steve@abita.co \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.