Re: [PATCH v3] module: Extend module_blacklist parameter to built-in modules

[email protected]
Newsgroups org.kernel.vger.linux-modules
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Iterating the `.initcall.modnames` array locklessly in `initcall_get_modname()` races with `free_initmem()`, causing a Use-After-Free for concurrently loaded modules.
- [High] The built-in module blacklisting functionality is completely disabled when CONFIG_MODULES=n.
--

commit aca1118f7ac6c8d2b798e7bb31a70a4f01638aee
Author: Aaron Tomlin <[email protected]>
Subject: module: Extend module_blacklist parameter to built-in modules

This patch extends the module_blacklist command-line parameter to apply
to built-in modules by checking them during early boot. It introduces a
new memory section to map initcalls to module names, allowing the kernel
to skip the initcall if the module name is present in the blacklist.

> diff --git a/include/linux/module.h b/include/linux/module.h
> index 7566815fabbe8..b9b0dc419aeeb 100644
> --- a/include/linux/module.h
> +++ b/include/linux/module.h
[ ... ]
> @@ -756,6 +756,15 @@ 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);
>  
> +#ifdef CONFIG_MODULES
> +extern bool module_is_blacklisted(const char *module_name);
> +#else
> +static inline bool module_is_blacklisted(const char *module_name)
> +{
> +	return false;
> +}
> +#endif

[Severity: High]
Does this defeat the purpose of blacklisting built-in modules on kernels
built without loadable module support?

If a kernel is built with CONFIG_MODULES=n, the command-line parsing and
state variable in kernel/module/main.c are not compiled. This stub will then
unconditionally return false, meaning the module_blacklist parameter will be
silently ignored for built-in modules on non-modular kernels.

[ ... ]
> diff --git a/init/main.c b/init/main.c
> index 96f93bb06c490..893b20ddcf658 100644
> --- a/init/main.c
> +++ b/init/main.c
[ ... ]
> @@ -1379,12 +1379,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 bool initmem_freed __ro_after_init = false;
> +
> +static const char *initcall_get_modname(initcall_t fn)
> +{
> +	struct initcall_modname *p;
> +
> +	if (initmem_freed)
> +		return NULL;
> +
> +	for (p = __start_initcall_modnames; p < __stop_initcall_modnames; p++) {
> +		if (p->initcall_fn == fn)
> +			return p->modname;
> +	}

[Severity: High]
Can this race with free_initmem() and cause a use-after-free if a module
is loaded concurrently?

In kernel_init(), free_initmem() is called just before setting initmem_freed
to true:

kernel_init()
    free_initmem();
    initmem_freed = true;

At this point in the boot sequence, the rootfs is mounted and user-mode
helpers are enabled. If a hardware interrupt triggers request_module()
concurrently, modprobe could execute and invoke the init_module syscall. 

When do_init_module() calls do_one_initcall(), it would end up in
initcall_get_modname(). Since initmem_freed is still false, it would
locklessly scan the .initcall.modnames section while it is actively being
freed by free_initmem().

[ ... ]
> @@ -1600,6 +1627,7 @@ static int __ref kernel_init(void *unused)
>  	kgdb_free_init_mem();
>  	exit_boot_config();
>  	free_initmem();
> +	initmem_freed = true;
>  	mark_readonly();
>  
>  	/*

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.