Cryptographic components must be properly initialized before use. This initialization is typically achieved through dedicated init functions registered via wrappers such as module_init() or late_initcall(). Traditionally, these init functions are executed automatically as part of the kernel boot sequence. However, now that the crypto code is moved into a standalone module (fips140.ko), there needs to be a way to collect and later execute them from within the module.
To collect these init functions, the init wrappers (module_init(), subsys_initcall(), late_initcall()) are modified so that when compiled for the FIPS module (under -DFIPS_MODULE), they automatically place the wrapped crypto init function pointer into a dedicated ELF section instead of the normal initcall mechanism. A custom linker script crypto/fips140/fips140.lds is introduced to organize these sections. Since the init functions must be called in proper ordering in a later patch (e.g., subsys_initcall before module_init, and module_init before late_initcall), the linker script allocates separate leveled sections (.fips_initcall0, .fips_initcall1, .fips_initcall2) with corresponding boundary symbols (e.g., __fips140_initcall0_start/end) to preserve the correct execution order. Signed-off-by: Jay Wang <[email protected]> --- Makefile | 2 +- crypto/fips140/fips140.lds | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/module.h | 23 +++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 crypto/fips140/fips140.lds diff --git a/Makefile b/Makefile index feacb5bd6235a..f3c43f87d6786 100644 --- a/Makefile +++ b/Makefile @@ -1378,7 +1378,7 @@ crypto/fips140/.fips140.symvers: fips140-ready @: modpost: crypto/fips140/.fips140.symvers quiet_cmd_ld_fips140 = LD [M] $@ - cmd_ld_fips140 = $(LD) -r $(KBUILD_LDFLAGS) $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) --build-id=none --whole-archive $< --no-whole-archive -o $@ + cmd_ld_fips140 = $(LD) -r $(KBUILD_LDFLAGS) $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) --build-id=none -T $(srctree)/crypto/fips140/fips140.lds --whole-archive $< --no-whole-archive -o $@ cmd_fips140_mod = ar -t $< > $@ diff --git a/crypto/fips140/fips140.lds b/crypto/fips140/fips140.lds new file mode 100644 index 0000000000000..6b5c63b1c6028 --- /dev/null +++ b/crypto/fips140/fips140.lds @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * FIPS 140 module initcall section layout. + * + * The overridden subsys_initcall/module_init/late_initcall macros + * (include/linux/module.h) place function pointers into these + * sections when compiled with FIPS_MODULE defined. + * + * Section mapping: + * .fips_initcall0 <- subsys_initcall() + * Syncs with kernel subsys_initcall (initcall level 4) + * .fips_initcall1 <- module_init() + * Syncs with kernel device_initcall (initcall level 6) + * .fips_initcall2 <- late_initcall() + * Syncs with kernel late_initcall (initcall level 7) + * + * The fips140 loader thread (fips140-loader.c) starts at + * arch_initcall_sync (level 3) and run_initcalls() in + * fips140-module.c executes each level in order, synchronizing + * with the kernel's initcall progression via wait queues. + */ + +SECTIONS { + .init.data : { + __fips140_initcalls_start = .; + __fips140_initcall0_start = .; + *(.fips_initcall0) + __fips140_initcall0_end = .; + __fips140_initcall1_start = .; + *(.fips_initcall1) + __fips140_initcall1_end = .; + __fips140_initcall2_start = .; + *(.fips_initcall2) + __fips140_initcall2_end = .; + __fips140_initcalls_end = .; + } +} \ No newline at end of file diff --git a/include/linux/module.h b/include/linux/module.h index 0ff24c45ef61d..6a10b70b5e92c 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -115,18 +115,40 @@ extern void cleanup_module(void); #define postcore_initcall(fn) module_init(fn) #define postcore_initcall_sync(fn) module_init(fn) #define arch_initcall(fn) module_init(fn) +#if defined(CONFIG_CRYPTO_FIPS140_EXTMOD) && defined(FIPS_MODULE) && !defined(FIPS140_CORE) +#define subsys_initcall(fn) \ + static initcall_t __used __section(".fips_initcall0") \ + __fips_##fn = fn; +#else #define subsys_initcall(fn) module_init(fn) +#endif #define subsys_initcall_sync(fn) module_init(fn) #define fs_initcall(fn) module_init(fn) #define fs_initcall_sync(fn) module_init(fn) #define rootfs_initcall(fn) module_init(fn) #define device_initcall(fn) module_init(fn) #define device_initcall_sync(fn) module_init(fn) +#if defined(CONFIG_CRYPTO_FIPS140_EXTMOD) && defined(FIPS_MODULE) && !defined(FIPS140_CORE) +#define late_initcall(fn) \ + static initcall_t __used __section(".fips_initcall2") \ + __fips_##fn = fn; +#else #define late_initcall(fn) module_init(fn) +#endif #define late_initcall_sync(fn) module_init(fn) #define console_initcall(fn) module_init(fn) +#if defined(CONFIG_CRYPTO_FIPS140_EXTMOD) && defined(FIPS_MODULE) && !defined(FIPS140_CORE) +/* FIPS module: place init/exit in special sections for fips140 loader */ +#define module_init(initfn) \ + static initcall_t __used __section(".fips_initcall1") \ + __fips_##initfn = initfn; + +#define module_exit(exitfn) \ + static unsigned long __used __section(".fips_exitcall") \ + __fips_##exitfn = (unsigned long)&exitfn; +#else /* Each module must use one module_init(). */ #define module_init(initfn) \ static inline initcall_t __maybe_unused __inittest(void) \ @@ -142,6 +164,7 @@ extern void cleanup_module(void); void cleanup_module(void) __copy(exitfn) \ __attribute__((alias(#exitfn))); \ ___ADDRESSABLE(cleanup_module, __exitdata); +#endif /* CONFIG_CRYPTO_FIPS140_EXTMOD && FIPS_MODULE && !FIPS140_CORE */ #endif -- 2.47.3
