On Mon, Aug 03, 2026 at 05:55:28PM +0200, Petr Pavlu wrote:
> > Design Considerations and Trade-offs:
> > 
> >     1.  LTO and CFI Compatibility vs. PREL32
> > 
> >         Previous iterations of this patch attempted to use top-level
> >         inline assembly to generate 32-bit relative offsets (PREL32) to
> >         save memory. However, raw inline assembly operates blindly
> >         outside of the C compiler's visibility. When compiled with
> >         CONFIG_LTO_CLANG or CONFIG_CFI_CLANG, the compiler applies
> >         symbol renaming and generates Control Flow Integrity stubs.
> >         The raw assembly string-matching fails to track these changes,
> >         resulting in undefined references or runtime address mismatches.
> > 
> >         To resolve this, we strictly use standard C structures to hold
> >         the function pointers. This natively allows the compiler to
> >         resolve LTO renaming and map CFI stubs correctly. We trade the
> >         minor spatial optimisation of PREL32 (using absolute 64-bit
> >         pointers instead) to guarantee architectural safety under modern
> >         compiler protections. Because this metadata is placed in an
> >         ".init" section and freed entirely after boot, the temporary
> >         memory overhead is negligible.
> > 
> >     2.  Architectural Safety and Elimination of Runtime Vulnerabilities:
> > 
> >         By embedding the boot-time blacklist check inside the
> >         do_one_initcall_builtin() __init wrapper function, we ensure
> >         the metadata lookup logic is exclusively invoked during early
> >         boot. This approach provides strict structural guarantees:
> >         - It inherently eliminates Use-After-Free (UAF) and race conditions
> >           since loadable modules (which execute post-boot and invoke
> >           do_one_initcall() directly) bypass this __init wrapper entirely.
> >         - It prevents modpost section mismatch warnings since the __init
> >           metadata is strictly accessed by other __init functions.
> >         - It mitigates Spectre v1 speculative execution vulnerabilities
> >           by guaranteeing the unprivileged runtime module loading path
> >           cannot speculatively branch into reclaimed .init.text 
> > instructions.
> 
> I suggest moving these design notes below the --- separator, together
> with the diffstat.

Acknowledged.

> > Signed-off-by: Aaron Tomlin <[email protected]>
> > ---
> >  include/asm-generic/vmlinux.lds.h |  4 ++-
> >  include/linux/init.h              | 27 +++++++++++++++-
> >  include/linux/module.h            |  4 ++-
> >  init/main.c                       | 54 +++++++++++++++++++++++++++++--
> >  kernel/module/main.c              | 22 +------------
> 
> The Rust module support in rust/macros/module.rs should be updated
> similarly to maintain feature parity.

Acknowledged.

> > +#define ___define_initcall_modname(fn, id, __sec)                  \
> > +   ____define_initcall_modname(fn, id, __sec, __initcall_id(fn))
> > +
> > +#define __define_initcall_modname(fn, id)                          \
> > +   ___define_initcall_modname(fn, id, .initcall##id)
> 
> These two macros can be merged into:

Acknowledged.

> #define __define_initcall_modname(fn, id)                             \
>       ___define_initcall_modname(fn, id, .initcall##id, __initcall_id(fn))
> 
> > +
> > +#define __builtin_module_initcall(fn)      __define_initcall_modname(fn, 6)
> > +
> > +#define ___define_initcall(fn, id, __sec)                          \
> >     __unique_initcall(fn, id, __sec, __initcall_id(fn))
> >  
> >  #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..ecc4db15ff4a 100644
> > --- a/include/linux/module.h
> > +++ b/include/linux/module.h
> > @@ -86,7 +86,7 @@ extern void cleanup_module(void);
> >   * builtin) or at module insertion time (if a module).  There can only
> >   * be one per module.
> >   */
> > -#define module_init(x)     __initcall(x);
> > +#define module_init(initfn)        __builtin_module_initcall(initfn);
> 
> Renaming the macro parameter from `x` to `initfn` is unnecessary in this
> patchset and also makes the preceding comment inconsistent, since it
> still refers to `x`.

Acknowledged.

> > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > index 46dd8d25a605..5c90ebedbf68 100644
> > --- a/kernel/module/main.c
> > +++ b/kernel/module/main.c
> > @@ -2919,26 +2919,6 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr,
> >     return 0;
> >  }
> >  
> > -/* module_blacklist is a comma-separated list of module names */
> > -static char *module_blacklist;
> > -static bool blacklisted(const char *module_name)
> > -{
> > -   const char *p;
> > -   size_t len;
> > -
> > -   if (!module_blacklist)
> > -           return false;
> > -
> > -   for (p = module_blacklist; *p; p += len) {
> > -           len = strcspn(p, ",");
> > -           if (strlen(module_name) == len && !memcmp(module_name, p, len))
> > -                   return true;
> > -           if (p[len] == ',')
> > -                   len++;
> > -   }
> > -   return false;
> > -}
> > -core_param(module_blacklist, module_blacklist, charp, 0400);
> >  
> 
> This still leaves two blank lines between module_frob_arch_sections()
> and layout_and_allocate(), instead of just one.

Acknowledged.


Kind regards,
-- 
Aaron Tomlin

Reply via email to