]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
module: Add compile-time check for embedded NUL characters
authorKees Cook <kees@kernel.org>
Fri, 10 Oct 2025 03:06:09 +0000 (20:06 -0700)
committerDaniel Gomez <da.gomez@samsung.com>
Wed, 5 Nov 2025 13:08:58 +0000 (14:08 +0100)
Long ago, the kernel module license checks were bypassed by embedding a
NUL character in the MODULE_LICENSE() string[1]. By using a string like
"GPL\0proprietary text", the kernel would only read "GPL" due to C string
termination at the NUL byte, allowing proprietary modules to avoid kernel
tainting and access GPL-only symbols.

The MODULE_INFO() macro stores these strings in the .modinfo ELF
section, and get_next_modinfo() uses strcmp()-family functions
which stop at the first NUL. This split the embedded string into two
separate .modinfo entries, with only the first part being processed by
license_is_gpl_compatible().

Add a compile-time check using static_assert that compares the full
string length (sizeof - 1) against __builtin_strlen(), which stops at
the first NUL. If they differ, compilation fails with a clear error
message.

While this check can still be circumvented by modifying the ELF binary
post-compilation, it prevents accidental embedded NULs and forces
intentional abuse to require deliberate binary manipulation rather than
simple source-level tricks.

Build tested with test modules containing both valid and invalid license
strings. The check correctly rejects:

    MODULE_LICENSE("GPL\0proprietary")

while accepting normal declarations:

    MODULE_LICENSE("GPL")

Link: https://lwn.net/Articles/82305/
Suggested-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Kees Cook <kees@kernel.org>
Reviewed-by: Daniel Gomez <da.gomez@samsung.com>
Reviewed-by: Aaron Tomlin <atomlin@atomlin.com>
Reviewed-by: Petr Pavlu <petr.pavlu@suse.com>
Tested-by: Daniel Gomez <da.gomez@samsung.com>
Signed-off-by: Daniel Gomez <da.gomez@samsung.com>
include/linux/moduleparam.h

index 6907aedc4f7484277127ba1b2539e99ffd12aacd..915f32f7d8888a9028b8767e0d90261e2f5083d4 100644 (file)
@@ -26,6 +26,9 @@
 
 /* Generic info of form tag = "info" */
 #define MODULE_INFO(tag, info)                                   \
+       static_assert(                                            \
+               sizeof(info) - 1 == __builtin_strlen(info),       \
+               "MODULE_INFO(" #tag ", ...) contains embedded NUL byte"); \
        static const char __UNIQUE_ID(modinfo)[]                          \
                __used __section(".modinfo") __aligned(1)                 \
                = __MODULE_INFO_PREFIX __stringify(tag) "=" info