From deffe1edba626d474fef38007c03646ca5876a0e Mon Sep 17 00:00:00 2001 From: Petr Pavlu Date: Fri, 13 Mar 2026 14:48:02 +0100 Subject: module: Fix freeing of charp module parameters when CONFIG_SYSFS=n When setting a charp module parameter, the param_set_charp() function allocates memory to store a copy of the input value. Later, when the module is potentially unloaded, the destroy_params() function is called to free this allocated memory. However, destroy_params() is available only when CONFIG_SYSFS=y, otherwise only a dummy variant is present. In the unlikely case that the kernel is configured with CONFIG_MODULES=y and CONFIG_SYSFS=n, this results in a memory leak of charp values when a module is unloaded. Fix this issue by making destroy_params() always available when CONFIG_MODULES=y. Rename the function to module_destroy_params() to clarify that it is intended for use by the module loader. Fixes: e180a6b7759a ("param: fix charp parameters set via sysfs") Signed-off-by: Petr Pavlu Signed-off-by: Sami Tolvanen --- include/linux/moduleparam.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 7d22d4c4ea2e..8667f72503d9 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -426,14 +426,9 @@ extern char *parse_args(const char *name, void *arg, parse_unknown_fn unknown); /* Called by module remove. */ -#ifdef CONFIG_SYSFS -extern void destroy_params(const struct kernel_param *params, unsigned num); -#else -static inline void destroy_params(const struct kernel_param *params, - unsigned num) -{ -} -#endif /* !CONFIG_SYSFS */ +#ifdef CONFIG_MODULES +void module_destroy_params(const struct kernel_param *params, unsigned int num); +#endif /* All the helper functions */ /* The macros to do compile-time type checking stolen from Jakub -- cgit v1.2.3 From 65f535501e2a3378629b8650eca553920de5e5a2 Mon Sep 17 00:00:00 2001 From: Petr Pavlu Date: Fri, 13 Mar 2026 14:48:03 +0100 Subject: module: Clean up parse_args() arguments * Use the preferred `unsigned int` over plain `unsigned` for the `num` parameter. * Synchronize the parameter names in moduleparam.h with the ones used by the implementation in params.c. Signed-off-by: Petr Pavlu Signed-off-by: Sami Tolvanen --- include/linux/moduleparam.h | 8 ++++---- kernel/params.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 8667f72503d9..604bc6e9f3a1 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -417,12 +417,12 @@ extern bool parameqn(const char *name1, const char *name2, size_t n); typedef int (*parse_unknown_fn)(char *param, char *val, const char *doing, void *arg); /* Called on module insert or kernel boot */ -extern char *parse_args(const char *name, +extern char *parse_args(const char *doing, char *args, const struct kernel_param *params, - unsigned num, - s16 level_min, - s16 level_max, + unsigned int num, + s16 min_level, + s16 max_level, void *arg, parse_unknown_fn unknown); /* Called by module remove. */ diff --git a/kernel/params.c b/kernel/params.c index c6a354d54213..74d620bc2521 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -161,7 +161,7 @@ static int parse_one(char *param, char *parse_args(const char *doing, char *args, const struct kernel_param *params, - unsigned num, + unsigned int num, s16 min_level, s16 max_level, void *arg, parse_unknown_fn unknown) -- cgit v1.2.3 From 44a063c00fb13cf1f2e8a53a2ab10b232a44954b Mon Sep 17 00:00:00 2001 From: Petr Pavlu Date: Fri, 13 Mar 2026 14:48:04 +0100 Subject: module: Remove extern keyword from param prototypes The external function declarations do not need the "extern" keyword. Remove it to align with the Linux kernel coding style and to silence the associated checkpatch warnings. Signed-off-by: Petr Pavlu Signed-off-by: Sami Tolvanen --- include/linux/moduleparam.h | 89 ++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 45 deletions(-) (limited to 'include/linux') diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 604bc6e9f3a1..075f28585074 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -317,8 +317,8 @@ struct kparam_array name, &__param_ops_##name, arg, perm, -1, 0) #ifdef CONFIG_SYSFS -extern void kernel_param_lock(struct module *mod); -extern void kernel_param_unlock(struct module *mod); +void kernel_param_lock(struct module *mod); +void kernel_param_unlock(struct module *mod); #else static inline void kernel_param_lock(struct module *mod) { @@ -398,7 +398,7 @@ static inline void kernel_param_unlock(struct module *mod) * Returns: true if the two parameter names are equal. * Dashes (-) are considered equal to underscores (_). */ -extern bool parameq(const char *name1, const char *name2); +bool parameq(const char *name1, const char *name2); /** * parameqn - checks if two parameter names match @@ -412,18 +412,18 @@ extern bool parameq(const char *name1, const char *name2); * are equal. * Dashes (-) are considered equal to underscores (_). */ -extern bool parameqn(const char *name1, const char *name2, size_t n); +bool parameqn(const char *name1, const char *name2, size_t n); typedef int (*parse_unknown_fn)(char *param, char *val, const char *doing, void *arg); /* Called on module insert or kernel boot */ -extern char *parse_args(const char *doing, - char *args, - const struct kernel_param *params, - unsigned int num, - s16 min_level, - s16 max_level, - void *arg, parse_unknown_fn unknown); +char *parse_args(const char *doing, + char *args, + const struct kernel_param *params, + unsigned int num, + s16 min_level, + s16 max_level, + void *arg, parse_unknown_fn unknown); /* Called by module remove. */ #ifdef CONFIG_MODULES @@ -437,78 +437,77 @@ void module_destroy_params(const struct kernel_param *params, unsigned int num); static inline type __always_unused *__check_##name(void) { return(p); } extern const struct kernel_param_ops param_ops_byte; -extern int param_set_byte(const char *val, const struct kernel_param *kp); -extern int param_get_byte(char *buffer, const struct kernel_param *kp); +int param_set_byte(const char *val, const struct kernel_param *kp); +int param_get_byte(char *buffer, const struct kernel_param *kp); #define param_check_byte(name, p) __param_check(name, p, unsigned char) extern const struct kernel_param_ops param_ops_short; -extern int param_set_short(const char *val, const struct kernel_param *kp); -extern int param_get_short(char *buffer, const struct kernel_param *kp); +int param_set_short(const char *val, const struct kernel_param *kp); +int param_get_short(char *buffer, const struct kernel_param *kp); #define param_check_short(name, p) __param_check(name, p, short) extern const struct kernel_param_ops param_ops_ushort; -extern int param_set_ushort(const char *val, const struct kernel_param *kp); -extern int param_get_ushort(char *buffer, const struct kernel_param *kp); +int param_set_ushort(const char *val, const struct kernel_param *kp); +int param_get_ushort(char *buffer, const struct kernel_param *kp); #define param_check_ushort(name, p) __param_check(name, p, unsigned short) extern const struct kernel_param_ops param_ops_int; -extern int param_set_int(const char *val, const struct kernel_param *kp); -extern int param_get_int(char *buffer, const struct kernel_param *kp); +int param_set_int(const char *val, const struct kernel_param *kp); +int param_get_int(char *buffer, const struct kernel_param *kp); #define param_check_int(name, p) __param_check(name, p, int) extern const struct kernel_param_ops param_ops_uint; -extern int param_set_uint(const char *val, const struct kernel_param *kp); -extern int param_get_uint(char *buffer, const struct kernel_param *kp); +int param_set_uint(const char *val, const struct kernel_param *kp); +int param_get_uint(char *buffer, const struct kernel_param *kp); int param_set_uint_minmax(const char *val, const struct kernel_param *kp, unsigned int min, unsigned int max); #define param_check_uint(name, p) __param_check(name, p, unsigned int) extern const struct kernel_param_ops param_ops_long; -extern int param_set_long(const char *val, const struct kernel_param *kp); -extern int param_get_long(char *buffer, const struct kernel_param *kp); +int param_set_long(const char *val, const struct kernel_param *kp); +int param_get_long(char *buffer, const struct kernel_param *kp); #define param_check_long(name, p) __param_check(name, p, long) extern const struct kernel_param_ops param_ops_ulong; -extern int param_set_ulong(const char *val, const struct kernel_param *kp); -extern int param_get_ulong(char *buffer, const struct kernel_param *kp); +int param_set_ulong(const char *val, const struct kernel_param *kp); +int param_get_ulong(char *buffer, const struct kernel_param *kp); #define param_check_ulong(name, p) __param_check(name, p, unsigned long) extern const struct kernel_param_ops param_ops_ullong; -extern int param_set_ullong(const char *val, const struct kernel_param *kp); -extern int param_get_ullong(char *buffer, const struct kernel_param *kp); +int param_set_ullong(const char *val, const struct kernel_param *kp); +int param_get_ullong(char *buffer, const struct kernel_param *kp); #define param_check_ullong(name, p) __param_check(name, p, unsigned long long) extern const struct kernel_param_ops param_ops_hexint; -extern int param_set_hexint(const char *val, const struct kernel_param *kp); -extern int param_get_hexint(char *buffer, const struct kernel_param *kp); +int param_set_hexint(const char *val, const struct kernel_param *kp); +int param_get_hexint(char *buffer, const struct kernel_param *kp); #define param_check_hexint(name, p) param_check_uint(name, p) extern const struct kernel_param_ops param_ops_charp; -extern int param_set_charp(const char *val, const struct kernel_param *kp); -extern int param_get_charp(char *buffer, const struct kernel_param *kp); -extern void param_free_charp(void *arg); +int param_set_charp(const char *val, const struct kernel_param *kp); +int param_get_charp(char *buffer, const struct kernel_param *kp); +void param_free_charp(void *arg); #define param_check_charp(name, p) __param_check(name, p, char *) /* We used to allow int as well as bool. We're taking that away! */ extern const struct kernel_param_ops param_ops_bool; -extern int param_set_bool(const char *val, const struct kernel_param *kp); -extern int param_get_bool(char *buffer, const struct kernel_param *kp); +int param_set_bool(const char *val, const struct kernel_param *kp); +int param_get_bool(char *buffer, const struct kernel_param *kp); #define param_check_bool(name, p) __param_check(name, p, bool) extern const struct kernel_param_ops param_ops_bool_enable_only; -extern int param_set_bool_enable_only(const char *val, - const struct kernel_param *kp); +int param_set_bool_enable_only(const char *val, const struct kernel_param *kp); /* getter is the same as for the regular bool */ #define param_check_bool_enable_only param_check_bool extern const struct kernel_param_ops param_ops_invbool; -extern int param_set_invbool(const char *val, const struct kernel_param *kp); -extern int param_get_invbool(char *buffer, const struct kernel_param *kp); +int param_set_invbool(const char *val, const struct kernel_param *kp); +int param_get_invbool(char *buffer, const struct kernel_param *kp); #define param_check_invbool(name, p) __param_check(name, p, bool) /* An int, which can only be set like a bool (though it shows as an int). */ extern const struct kernel_param_ops param_ops_bint; -extern int param_set_bint(const char *val, const struct kernel_param *kp); +int param_set_bint(const char *val, const struct kernel_param *kp); #define param_get_bint param_get_int #define param_check_bint param_check_int @@ -615,19 +614,19 @@ enum hwparam_type { extern const struct kernel_param_ops param_array_ops; extern const struct kernel_param_ops param_ops_string; -extern int param_set_copystring(const char *val, const struct kernel_param *); -extern int param_get_string(char *buffer, const struct kernel_param *kp); +int param_set_copystring(const char *val, const struct kernel_param *kp); +int param_get_string(char *buffer, const struct kernel_param *kp); /* for exporting parameters in /sys/module/.../parameters */ struct module; #if defined(CONFIG_SYSFS) && defined(CONFIG_MODULES) -extern int module_param_sysfs_setup(struct module *mod, - const struct kernel_param *kparam, - unsigned int num_params); +int module_param_sysfs_setup(struct module *mod, + const struct kernel_param *kparam, + unsigned int num_params); -extern void module_param_sysfs_remove(struct module *mod); +void module_param_sysfs_remove(struct module *mod); #else static inline int module_param_sysfs_setup(struct module *mod, const struct kernel_param *kparam, -- cgit v1.2.3 From 3fe1dcbc2d20c5dbc581c0bb458e05365bfffcf7 Mon Sep 17 00:00:00 2001 From: Nicholas Sielicki Date: Sat, 7 Mar 2026 03:00:09 -0600 Subject: module: expose imported namespaces via sysfs Add /sys/module/*/import_ns to expose imported namespaces for currently loaded modules. The file contains one namespace per line and only exists for modules that import at least one namespace. Previously, the only way for userspace to inspect the symbol namespaces a module imports is to locate the .ko on disk and invoke modinfo(8) to decompress/parse the metadata. The kernel validated namespaces at load time, but it was otherwise discarded. Exposing this data via sysfs provides a runtime mechanism to verify which namespaces are being used by modules. For example, this allows userspace to audit driver API access in Android GKI, which uses symbol namespaces to restrict vendor drivers from using specific kernel interfaces (e.g., direct filesystem access). Signed-off-by: Nicholas Sielicki [Sami: Updated the commit message to explain motivation.] Signed-off-by: Sami Tolvanen --- Documentation/ABI/testing/sysfs-module | 9 +++++ include/linux/module.h | 1 + kernel/module/main.c | 69 +++++++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/Documentation/ABI/testing/sysfs-module b/Documentation/ABI/testing/sysfs-module index 6bc9af6229f0..d5b7d19bd310 100644 --- a/Documentation/ABI/testing/sysfs-module +++ b/Documentation/ABI/testing/sysfs-module @@ -48,6 +48,15 @@ Contact: Kay Sievers Description: Show the initialization state(live, coming, going) of the module. +What: /sys/module/*/import_ns +Date: January 2026 +KernelVersion: 7.1 +Contact: linux-modules@vger.kernel.org +Description: List of symbol namespaces imported by this module via + MODULE_IMPORT_NS(). Each namespace appears on a separate line. + This file only exists for modules that import at least one + namespace. + What: /sys/module/*/taint Date: Jan 2012 KernelVersion: 3.3 diff --git a/include/linux/module.h b/include/linux/module.h index 14f391b186c6..60ed1c3e0ed9 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -413,6 +413,7 @@ struct module { struct module_attribute *modinfo_attrs; const char *version; const char *srcversion; + const char *imported_namespaces; struct kobject *holders_dir; /* Exported symbols */ diff --git a/kernel/module/main.c b/kernel/module/main.c index ef2e2130972f..fc033137863d 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -607,6 +607,36 @@ static const struct module_attribute modinfo_##field = { \ MODINFO_ATTR(version); MODINFO_ATTR(srcversion); +static void setup_modinfo_import_ns(struct module *mod, const char *s) +{ + mod->imported_namespaces = NULL; +} + +static ssize_t show_modinfo_import_ns(const struct module_attribute *mattr, + struct module_kobject *mk, char *buffer) +{ + return sysfs_emit(buffer, "%s\n", mk->mod->imported_namespaces); +} + +static int modinfo_import_ns_exists(struct module *mod) +{ + return mod->imported_namespaces != NULL; +} + +static void free_modinfo_import_ns(struct module *mod) +{ + kfree(mod->imported_namespaces); + mod->imported_namespaces = NULL; +} + +static const struct module_attribute modinfo_import_ns = { + .attr = { .name = "import_ns", .mode = 0444 }, + .show = show_modinfo_import_ns, + .setup = setup_modinfo_import_ns, + .test = modinfo_import_ns_exists, + .free = free_modinfo_import_ns, +}; + static struct { char name[MODULE_NAME_LEN]; char taints[MODULE_FLAGS_BUF_SIZE]; @@ -1058,6 +1088,7 @@ const struct module_attribute *const modinfo_attrs[] = { &module_uevent, &modinfo_version, &modinfo_srcversion, + &modinfo_import_ns, &modinfo_initstate, &modinfo_coresize, #ifdef CONFIG_ARCH_WANTS_MODULES_DATA_IN_VMALLOC @@ -1760,11 +1791,43 @@ static void module_license_taint_check(struct module *mod, const char *license) } } +static int copy_modinfo_import_ns(struct module *mod, struct load_info *info) +{ + char *ns; + size_t len, total_len = 0; + char *buf, *p; + + for_each_modinfo_entry(ns, info, "import_ns") + total_len += strlen(ns) + 1; + + if (!total_len) { + mod->imported_namespaces = NULL; + return 0; + } + + buf = kmalloc(total_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + p = buf; + for_each_modinfo_entry(ns, info, "import_ns") { + len = strlen(ns); + memcpy(p, ns, len); + p += len; + *p++ = '\n'; + } + /* Replace trailing newline with null terminator. */ + *(p - 1) = '\0'; + + mod->imported_namespaces = buf; + return 0; +} + static int setup_modinfo(struct module *mod, struct load_info *info) { const struct module_attribute *attr; char *imported_namespace; - int i; + int i, err; for (i = 0; (attr = modinfo_attrs[i]); i++) { if (attr->setup) @@ -1783,6 +1846,10 @@ static int setup_modinfo(struct module *mod, struct load_info *info) } } + err = copy_modinfo_import_ns(mod, info); + if (err) + return err; + return 0; } -- cgit v1.2.3 From 8988913aacee82e5401bf3b96839731982dcbde7 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Thu, 5 Mar 2026 10:31:38 +0100 Subject: module: Drop unused signature types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only PKCS#7 signatures are used today. Remove the unused enum values. As this enum is used in on-disk data, preserve the numeric value. Signed-off-by: Thomas Weißschuh Reviewed-by: Petr Pavlu Reviewed-by: Nicolas Schier Signed-off-by: Sami Tolvanen --- include/linux/module_signature.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/module_signature.h b/include/linux/module_signature.h index 7eb4b00381ac..820cc1473383 100644 --- a/include/linux/module_signature.h +++ b/include/linux/module_signature.h @@ -15,9 +15,7 @@ #define MODULE_SIG_STRING "~Module signature appended~\n" enum pkey_id_type { - PKEY_ID_PGP, /* OpenPGP generated key ID */ - PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ - PKEY_ID_PKCS7, /* Signature in PKCS#7 message */ + PKEY_ID_PKCS7 = 2, /* Signature in PKCS#7 message */ }; /* -- cgit v1.2.3 From acd87264af525dba6e9355310e8acdf066a5f6b5 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Thu, 5 Mar 2026 10:31:39 +0100 Subject: module: Give 'enum pkey_id_type' a more specific name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enum originates in generic cryptographic code and has a very generic name. Nowadays it is only used for module signatures. As this enum is going to be exposed in a UAPI header, give it a more specific name for clarity and consistency. Signed-off-by: Thomas Weißschuh Reviewed-by: Petr Pavlu Reviewed-by: Nicolas Schier Signed-off-by: Sami Tolvanen --- arch/s390/kernel/machine_kexec_file.c | 2 +- include/linux/module_signature.h | 6 +++--- kernel/module_signature.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c index 1bf59c3f0e2b..667ee9279e23 100644 --- a/arch/s390/kernel/machine_kexec_file.c +++ b/arch/s390/kernel/machine_kexec_file.c @@ -53,7 +53,7 @@ int s390_verify_sig(const char *kernel, unsigned long kernel_len) return -EKEYREJECTED; kernel_len -= sig_len; - if (ms->id_type != PKEY_ID_PKCS7) + if (ms->id_type != MODULE_SIGNATURE_TYPE_PKCS7) return -EKEYREJECTED; if (ms->algo != 0 || diff --git a/include/linux/module_signature.h b/include/linux/module_signature.h index 820cc1473383..c3a05d4cfe67 100644 --- a/include/linux/module_signature.h +++ b/include/linux/module_signature.h @@ -14,8 +14,8 @@ /* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ #define MODULE_SIG_STRING "~Module signature appended~\n" -enum pkey_id_type { - PKEY_ID_PKCS7 = 2, /* Signature in PKCS#7 message */ +enum module_signature_type { + MODULE_SIGNATURE_TYPE_PKCS7 = 2, /* Signature in PKCS#7 message */ }; /* @@ -31,7 +31,7 @@ enum pkey_id_type { struct module_signature { u8 algo; /* Public-key crypto algorithm [0] */ u8 hash; /* Digest algorithm [0] */ - u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */ + u8 id_type; /* Key identifier type [enum module_signature_type] */ u8 signer_len; /* Length of signer's name [0] */ u8 key_id_len; /* Length of key identifier [0] */ u8 __pad[3]; diff --git a/kernel/module_signature.c b/kernel/module_signature.c index 00132d12487c..a0eee2fe4368 100644 --- a/kernel/module_signature.c +++ b/kernel/module_signature.c @@ -24,7 +24,7 @@ int mod_check_sig(const struct module_signature *ms, size_t file_len, if (be32_to_cpu(ms->sig_len) >= file_len - sizeof(*ms)) return -EBADMSG; - if (ms->id_type != PKEY_ID_PKCS7) { + if (ms->id_type != MODULE_SIGNATURE_TYPE_PKCS7) { pr_err("%s: not signed with expected PKCS#7 message\n", name); return -ENOPKG; -- cgit v1.2.3 From 2ae4ea2d9aaf25cb74fbc23450b1b8f0a5b7aa89 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Thu, 5 Mar 2026 10:31:40 +0100 Subject: module: Give MODULE_SIG_STRING a more descriptive name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The purpose of the constant it is not entirely clear from its name. As this constant is going to be exposed in a UAPI header, give it a more specific name for clarity. As all its users call it 'marker', use that wording in the constant itself. Signed-off-by: Thomas Weißschuh Reviewed-by: Petr Pavlu Reviewed-by: Nicolas Schier Signed-off-by: Sami Tolvanen --- arch/s390/kernel/machine_kexec_file.c | 4 ++-- include/linux/module_signature.h | 2 +- kernel/module/signing.c | 4 ++-- security/integrity/ima/ima_modsig.c | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c index 667ee9279e23..6f0852d5a3a9 100644 --- a/arch/s390/kernel/machine_kexec_file.c +++ b/arch/s390/kernel/machine_kexec_file.c @@ -28,7 +28,7 @@ const struct kexec_file_ops * const kexec_file_loaders[] = { #ifdef CONFIG_KEXEC_SIG int s390_verify_sig(const char *kernel, unsigned long kernel_len) { - const unsigned long marker_len = sizeof(MODULE_SIG_STRING) - 1; + const unsigned long marker_len = sizeof(MODULE_SIGNATURE_MARKER) - 1; struct module_signature *ms; unsigned long sig_len; int ret; @@ -40,7 +40,7 @@ int s390_verify_sig(const char *kernel, unsigned long kernel_len) if (marker_len > kernel_len) return -EKEYREJECTED; - if (memcmp(kernel + kernel_len - marker_len, MODULE_SIG_STRING, + if (memcmp(kernel + kernel_len - marker_len, MODULE_SIGNATURE_MARKER, marker_len)) return -EKEYREJECTED; kernel_len -= marker_len; diff --git a/include/linux/module_signature.h b/include/linux/module_signature.h index c3a05d4cfe67..915549c779dc 100644 --- a/include/linux/module_signature.h +++ b/include/linux/module_signature.h @@ -12,7 +12,7 @@ #include /* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ -#define MODULE_SIG_STRING "~Module signature appended~\n" +#define MODULE_SIGNATURE_MARKER "~Module signature appended~\n" enum module_signature_type { MODULE_SIGNATURE_TYPE_PKCS7 = 2, /* Signature in PKCS#7 message */ diff --git a/kernel/module/signing.c b/kernel/module/signing.c index a2ff4242e623..590ba29c85ab 100644 --- a/kernel/module/signing.c +++ b/kernel/module/signing.c @@ -70,7 +70,7 @@ int mod_verify_sig(const void *mod, struct load_info *info) int module_sig_check(struct load_info *info, int flags) { int err = -ENODATA; - const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; + const unsigned long markerlen = sizeof(MODULE_SIGNATURE_MARKER) - 1; const char *reason; const void *mod = info->hdr; bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS | @@ -81,7 +81,7 @@ int module_sig_check(struct load_info *info, int flags) */ if (!mangled_module && info->len > markerlen && - memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) { + memcmp(mod + info->len - markerlen, MODULE_SIGNATURE_MARKER, markerlen) == 0) { /* We truncate the module to discard the signature */ info->len -= markerlen; err = mod_verify_sig(mod, info); diff --git a/security/integrity/ima/ima_modsig.c b/security/integrity/ima/ima_modsig.c index 9aa92fd35a03..632c746fd81e 100644 --- a/security/integrity/ima/ima_modsig.c +++ b/security/integrity/ima/ima_modsig.c @@ -40,7 +40,7 @@ struct modsig { int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, struct modsig **modsig) { - const size_t marker_len = strlen(MODULE_SIG_STRING); + const size_t marker_len = strlen(MODULE_SIGNATURE_MARKER); const struct module_signature *sig; struct modsig *hdr; size_t sig_len; @@ -51,7 +51,7 @@ int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, return -ENOENT; p = buf + buf_len - marker_len; - if (memcmp(p, MODULE_SIG_STRING, marker_len)) + if (memcmp(p, MODULE_SIGNATURE_MARKER, marker_len)) return -ENOENT; buf_len -= marker_len; @@ -105,7 +105,7 @@ void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size) * Provide the file contents (minus the appended sig) so that the PKCS7 * code can calculate the file hash. */ - size -= modsig->raw_pkcs7_len + strlen(MODULE_SIG_STRING) + + size -= modsig->raw_pkcs7_len + strlen(MODULE_SIGNATURE_MARKER) + sizeof(struct module_signature); rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size); if (rc) -- cgit v1.2.3 From f9909cf0a2dcc9e99377f3fcc965ccd93e518e34 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Thu, 5 Mar 2026 10:31:41 +0100 Subject: module: Move 'struct module_signature' to UAPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This structure definition is used outside the kernel proper. For example in kmod and the kernel build environment. To allow reuse, move it to a new UAPI header. While it is not a true UAPI, it is a common practice to have non-UAPI interface definitions in the kernel's UAPI headers. Signed-off-by: Thomas Weißschuh Reviewed-by: Petr Pavlu Reviewed-by: Nicolas Schier Signed-off-by: Sami Tolvanen --- include/linux/module_signature.h | 28 +----------------------- include/uapi/linux/module_signature.h | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 27 deletions(-) create mode 100644 include/uapi/linux/module_signature.h (limited to 'include/linux') diff --git a/include/linux/module_signature.h b/include/linux/module_signature.h index 915549c779dc..db335d46787f 100644 --- a/include/linux/module_signature.h +++ b/include/linux/module_signature.h @@ -10,33 +10,7 @@ #define _LINUX_MODULE_SIGNATURE_H #include - -/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ -#define MODULE_SIGNATURE_MARKER "~Module signature appended~\n" - -enum module_signature_type { - MODULE_SIGNATURE_TYPE_PKCS7 = 2, /* Signature in PKCS#7 message */ -}; - -/* - * Module signature information block. - * - * The constituents of the signature section are, in order: - * - * - Signer's name - * - Key identifier - * - Signature data - * - Information block - */ -struct module_signature { - u8 algo; /* Public-key crypto algorithm [0] */ - u8 hash; /* Digest algorithm [0] */ - u8 id_type; /* Key identifier type [enum module_signature_type] */ - u8 signer_len; /* Length of signer's name [0] */ - u8 key_id_len; /* Length of key identifier [0] */ - u8 __pad[3]; - __be32 sig_len; /* Length of signature data */ -}; +#include int mod_check_sig(const struct module_signature *ms, size_t file_len, const char *name); diff --git a/include/uapi/linux/module_signature.h b/include/uapi/linux/module_signature.h new file mode 100644 index 000000000000..634c9f1c8fc2 --- /dev/null +++ b/include/uapi/linux/module_signature.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Module signature handling. + * + * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#ifndef _UAPI_LINUX_MODULE_SIGNATURE_H +#define _UAPI_LINUX_MODULE_SIGNATURE_H + +#include + +/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ +#define MODULE_SIGNATURE_MARKER "~Module signature appended~\n" + +enum module_signature_type { + MODULE_SIGNATURE_TYPE_PKCS7 = 2, /* Signature in PKCS#7 message */ +}; + +/* + * Module signature information block. + * + * The constituents of the signature section are, in order: + * + * - Signer's name + * - Key identifier + * - Signature data + * - Information block + */ +struct module_signature { + __u8 algo; /* Public-key crypto algorithm [0] */ + __u8 hash; /* Digest algorithm [0] */ + __u8 id_type; /* Key identifier type [enum module_signature_type] */ + __u8 signer_len; /* Length of signer's name [0] */ + __u8 key_id_len; /* Length of key identifier [0] */ + __u8 __pad[3]; + __be32 sig_len; /* Length of signature data */ +}; + +#endif /* _UAPI_LINUX_MODULE_SIGNATURE_H */ -- cgit v1.2.3 From 10a4eb5882ba16164ece86d99486084f02f148bb Mon Sep 17 00:00:00 2001 From: Siddharth Nayyar Date: Thu, 26 Mar 2026 21:25:02 +0000 Subject: module: define ksym_flags enumeration to represent kernel symbol flags The core architectural issue with kernel symbol flags is our reliance on splitting the main symbol table, ksymtab. To handle a single boolean property, such as GPL-only, all exported symbols are split across two separate tables: __ksymtab and __ksymtab_gpl. This design forces the module loader to perform a separate search on each of these tables for every symbol it needs, for vmlinux and for all previously loaded modules. This approach is fundamentally not scalable. If we were to introduce a second flag, we would need four distinct symbol tables. For n boolean flags, this model requires an exponential growth to 2^n tables, dramatically increasing complexity. Another consequence of this fragmentation is degraded performance. For example, a binary search on the symbol table of vmlinux, that would take only 14 comparison steps (assuming ~2^14 or 16K symbols) in a unified table, can require up to 26 steps when spread across two tables (assuming both tables have ~2^13 symbols). This performance penalty worsens as more flags are added. To address this, symbol flags is an enumeration used to represent flags as a bitset, for example a flag to tell if a symbol is GPL only. The said bitset is introduced in subsequent patches and will contain values of kernel symbol flags. These bitset will then be used to infer flag values rather than fragmenting ksymtab for separating symbols with different flag values, thereby eliminating the need to fragment the ksymtab. Link: https://lore.kernel.org/r/20260326-kflagstab-v5-0-fa0796fe88d9@google.com Signed-off-by: Siddharth Nayyar Reviewed-by: Petr Pavlu [Sami: Updated the commit message to explain the use case for the series.] Signed-off-by: Sami Tolvanen --- include/linux/module_symbol.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include/linux') diff --git a/include/linux/module_symbol.h b/include/linux/module_symbol.h index 77c9895b9ddb..574609aced99 100644 --- a/include/linux/module_symbol.h +++ b/include/linux/module_symbol.h @@ -2,6 +2,11 @@ #ifndef _LINUX_MODULE_SYMBOL_H #define _LINUX_MODULE_SYMBOL_H +/* Kernel symbol flags bitset. */ +enum ksym_flags { + KSYM_FLAG_GPL_ONLY = 1 << 0, +}; + /* This ignores the intensely annoying "mapping symbols" found in ELF files. */ static inline bool is_mapping_symbol(const char *str) { -- cgit v1.2.3 From 16d0e04f546ffba78c74bbfeb57d93147bcaf2c5 Mon Sep 17 00:00:00 2001 From: Siddharth Nayyar Date: Thu, 26 Mar 2026 21:25:04 +0000 Subject: module: populate kflagstab in modpost This patch adds the ability to create entries for kernel symbol flag bitsets in kflagstab. Modpost populates only the GPL-only flag for now. Signed-off-by: Siddharth Nayyar Reviewed-by: Petr Pavlu Signed-off-by: Sami Tolvanen --- include/linux/export-internal.h | 7 +++++++ scripts/mod/modpost.c | 8 ++++++++ 2 files changed, 15 insertions(+) (limited to 'include/linux') diff --git a/include/linux/export-internal.h b/include/linux/export-internal.h index d445705ac13c..4123c7592404 100644 --- a/include/linux/export-internal.h +++ b/include/linux/export-internal.h @@ -69,4 +69,11 @@ ".long " #crc "\n" \ ".previous" "\n") +#define SYMBOL_FLAGS(sym, flags) \ + asm(" .section \"___kflagstab+" #sym "\",\"a\"" "\n" \ + "__flags_" #sym ":" "\n" \ + " .byte " #flags "\n" \ + " .previous" "\n" \ + ) + #endif /* __LINUX_EXPORT_INTERNAL_H__ */ diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 0c25b5ad497b..1d721fe67caf 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -244,6 +244,11 @@ static struct symbol *alloc_symbol(const char *name) return s; } +static uint8_t get_symbol_flags(const struct symbol *sym) +{ + return sym->is_gpl_only ? KSYM_FLAG_GPL_ONLY : 0; +} + /* For the hash of exported symbols */ static void hash_add_symbol(struct symbol *sym) { @@ -1874,6 +1879,9 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod) buf_printf(buf, "KSYMTAB_%s(%s, \"%s\", \"%s\");\n", sym->is_func ? "FUNC" : "DATA", sym->name, sym->is_gpl_only ? "_gpl" : "", sym->namespace); + + buf_printf(buf, "SYMBOL_FLAGS(%s, 0x%02x);\n", + sym->name, get_symbol_flags(sym)); } if (!modversions) -- cgit v1.2.3 From 55fcb926b6d8b5cfb40873e4840a69961db1bb69 Mon Sep 17 00:00:00 2001 From: Siddharth Nayyar Date: Thu, 26 Mar 2026 21:25:05 +0000 Subject: module: use kflagstab instead of *_gpl sections Read kflagstab section for vmlinux and modules to determine whether kernel symbols are GPL only. This patch eliminates the need for fragmenting the ksymtab for infering the value of GPL-only symbol flag, henceforth stop populating *_gpl versions of the ksymtab and kcrctab in modpost. Signed-off-by: Siddharth Nayyar Reviewed-by: Petr Pavlu Signed-off-by: Sami Tolvanen --- include/linux/export-internal.h | 21 ++++++++-------- include/linux/module.h | 1 + kernel/module/internal.h | 1 + kernel/module/main.c | 55 ++++++++++++++++++++++------------------- scripts/mod/modpost.c | 8 +++--- 5 files changed, 46 insertions(+), 40 deletions(-) (limited to 'include/linux') diff --git a/include/linux/export-internal.h b/include/linux/export-internal.h index 4123c7592404..726054614752 100644 --- a/include/linux/export-internal.h +++ b/include/linux/export-internal.h @@ -37,14 +37,14 @@ * section flag requires it. Use '%progbits' instead of '@progbits' since the * former apparently works on all arches according to the binutils source. */ -#define __KSYMTAB(name, sym, sec, ns) \ +#define __KSYMTAB(name, sym, ns) \ asm(" .section \"__ksymtab_strings\",\"aMS\",%progbits,1" "\n" \ "__kstrtab_" #name ":" "\n" \ " .asciz \"" #name "\"" "\n" \ "__kstrtabns_" #name ":" "\n" \ " .asciz \"" ns "\"" "\n" \ " .previous" "\n" \ - " .section \"___ksymtab" sec "+" #name "\", \"a\"" "\n" \ + " .section \"___ksymtab+" #name "\", \"a\"" "\n" \ __KSYM_ALIGN "\n" \ "__ksymtab_" #name ":" "\n" \ __KSYM_REF(sym) "\n" \ @@ -59,15 +59,16 @@ #define KSYM_FUNC(name) name #endif -#define KSYMTAB_FUNC(name, sec, ns) __KSYMTAB(name, KSYM_FUNC(name), sec, ns) -#define KSYMTAB_DATA(name, sec, ns) __KSYMTAB(name, name, sec, ns) +#define KSYMTAB_FUNC(name, ns) __KSYMTAB(name, KSYM_FUNC(name), ns) +#define KSYMTAB_DATA(name, ns) __KSYMTAB(name, name, ns) -#define SYMBOL_CRC(sym, crc, sec) \ - asm(".section \"___kcrctab" sec "+" #sym "\",\"a\"" "\n" \ - ".balign 4" "\n" \ - "__crc_" #sym ":" "\n" \ - ".long " #crc "\n" \ - ".previous" "\n") +#define SYMBOL_CRC(sym, crc) \ + asm(" .section \"___kcrctab+" #sym "\",\"a\"" "\n" \ + " .balign 4" "\n" \ + "__crc_" #sym ":" "\n" \ + " .long " #crc "\n" \ + " .previous" "\n" \ + ) #define SYMBOL_FLAGS(sym, flags) \ asm(" .section \"___kflagstab+" #sym "\",\"a\"" "\n" \ diff --git a/include/linux/module.h b/include/linux/module.h index 60ed1c3e0ed9..917b29332e15 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -419,6 +419,7 @@ struct module { /* Exported symbols */ const struct kernel_symbol *syms; const u32 *crcs; + const u8 *flagstab; unsigned int num_syms; #ifdef CONFIG_ARCH_USES_CFI_TRAPS diff --git a/kernel/module/internal.h b/kernel/module/internal.h index 618202578b42..69b84510e097 100644 --- a/kernel/module/internal.h +++ b/kernel/module/internal.h @@ -57,6 +57,7 @@ extern const struct kernel_symbol __start___ksymtab_gpl[]; extern const struct kernel_symbol __stop___ksymtab_gpl[]; extern const u32 __start___kcrctab[]; extern const u32 __start___kcrctab_gpl[]; +extern const u8 __start___kflagstab[]; #define KMOD_PATH_LEN 256 extern char modprobe_path[]; diff --git a/kernel/module/main.c b/kernel/module/main.c index fc033137863d..c243d6b79cdd 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -87,7 +88,7 @@ struct mod_tree_root mod_tree __cacheline_aligned = { struct symsearch { const struct kernel_symbol *start, *stop; const u32 *crcs; - enum mod_license license; + const u8 *flagstab; }; /* @@ -364,19 +365,21 @@ static bool find_exported_symbol_in_section(const struct symsearch *syms, struct find_symbol_arg *fsa) { struct kernel_symbol *sym; - - if (!fsa->gplok && syms->license == GPL_ONLY) - return false; + u8 sym_flags; sym = bsearch(fsa->name, syms->start, syms->stop - syms->start, sizeof(struct kernel_symbol), cmp_name); if (!sym) return false; + sym_flags = *(syms->flagstab + (sym - syms->start)); + if (!fsa->gplok && (sym_flags & KSYM_FLAG_GPL_ONLY)) + return false; + fsa->owner = owner; fsa->crc = symversion(syms->crcs, sym - syms->start); fsa->sym = sym; - fsa->license = syms->license; + fsa->license = (sym_flags & KSYM_FLAG_GPL_ONLY) ? GPL_ONLY : NOT_GPL_ONLY; return true; } @@ -387,36 +390,31 @@ static bool find_exported_symbol_in_section(const struct symsearch *syms, */ bool find_symbol(struct find_symbol_arg *fsa) { - static const struct symsearch arr[] = { - { __start___ksymtab, __stop___ksymtab, __start___kcrctab, - NOT_GPL_ONLY }, - { __start___ksymtab_gpl, __stop___ksymtab_gpl, - __start___kcrctab_gpl, - GPL_ONLY }, + const struct symsearch syms = { + .start = __start___ksymtab, + .stop = __stop___ksymtab, + .crcs = __start___kcrctab, + .flagstab = __start___kflagstab, }; struct module *mod; - unsigned int i; - for (i = 0; i < ARRAY_SIZE(arr); i++) - if (find_exported_symbol_in_section(&arr[i], NULL, fsa)) - return true; + if (find_exported_symbol_in_section(&syms, NULL, fsa)) + return true; list_for_each_entry_rcu(mod, &modules, list, lockdep_is_held(&module_mutex)) { - struct symsearch arr[] = { - { mod->syms, mod->syms + mod->num_syms, mod->crcs, - NOT_GPL_ONLY }, - { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms, - mod->gpl_crcs, - GPL_ONLY }, + const struct symsearch syms = { + .start = mod->syms, + .stop = mod->syms + mod->num_syms, + .crcs = mod->crcs, + .flagstab = mod->flagstab, }; if (mod->state == MODULE_STATE_UNFORMED) continue; - for (i = 0; i < ARRAY_SIZE(arr); i++) - if (find_exported_symbol_in_section(&arr[i], mod, fsa)) - return true; + if (find_exported_symbol_in_section(&syms, mod, fsa)) + return true; } pr_debug("Failed to find symbol %s\n", fsa->name); @@ -2681,6 +2679,7 @@ static int find_module_sections(struct module *mod, struct load_info *info) sizeof(*mod->gpl_syms), &mod->num_gpl_syms); mod->gpl_crcs = section_addr(info, "__kcrctab_gpl"); + mod->flagstab = section_addr(info, "__kflagstab"); #ifdef CONFIG_CONSTRUCTORS mod->ctors = section_objs(info, ".ctors", @@ -2884,8 +2883,12 @@ out_err: return ret; } -static int check_export_symbol_versions(struct module *mod) +static int check_export_symbol_sections(struct module *mod) { + if (mod->num_syms && !mod->flagstab) { + pr_err("%s: no flags for exported symbols\n", mod->name); + return -ENOEXEC; + } #ifdef CONFIG_MODVERSIONS if ((mod->num_syms && !mod->crcs) || (mod->num_gpl_syms && !mod->gpl_crcs)) { @@ -3501,7 +3504,7 @@ static int load_module(struct load_info *info, const char __user *uargs, if (err) goto free_unload; - err = check_export_symbol_versions(mod); + err = check_export_symbol_sections(mod); if (err) goto free_unload; diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 1d721fe67caf..9d96acce60a8 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1876,9 +1876,9 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod) if (trim_unused_exports && !sym->used) continue; - buf_printf(buf, "KSYMTAB_%s(%s, \"%s\", \"%s\");\n", + buf_printf(buf, "KSYMTAB_%s(%s, \"%s\");\n", sym->is_func ? "FUNC" : "DATA", sym->name, - sym->is_gpl_only ? "_gpl" : "", sym->namespace); + sym->namespace); buf_printf(buf, "SYMBOL_FLAGS(%s, 0x%02x);\n", sym->name, get_symbol_flags(sym)); @@ -1899,8 +1899,8 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod) sym->name, mod->name, mod->is_vmlinux ? "" : ".ko", sym->name); - buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n", - sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : ""); + buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x);\n", + sym->name, sym->crc); } } -- cgit v1.2.3 From b4760ff2a5e4351c59d185967735f59c0b0bd7f6 Mon Sep 17 00:00:00 2001 From: Siddharth Nayyar Date: Thu, 26 Mar 2026 21:25:06 +0000 Subject: module: deprecate usage of *_gpl sections in module loader The *_gpl section are not being used populated by modpost anymore. Hence the module loader doesn't need to find and process these sections in modules. This patch also simplifies symbol finding logic in module loader since *_gpl sections don't have to be searched anymore. Signed-off-by: Siddharth Nayyar Reviewed-by: Petr Pavlu Signed-off-by: Sami Tolvanen --- include/linux/module.h | 3 --- kernel/module/internal.h | 3 --- kernel/module/main.c | 46 ++++++++++++++++++---------------------------- 3 files changed, 18 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/include/linux/module.h b/include/linux/module.h index 917b29332e15..7566815fabbe 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -435,9 +435,6 @@ struct module { unsigned int num_kp; /* GPL-only exported symbols. */ - unsigned int num_gpl_syms; - const struct kernel_symbol *gpl_syms; - const u32 *gpl_crcs; bool using_gplonly_symbols; #ifdef CONFIG_MODULE_SIG diff --git a/kernel/module/internal.h b/kernel/module/internal.h index 69b84510e097..061161cc79d9 100644 --- a/kernel/module/internal.h +++ b/kernel/module/internal.h @@ -53,10 +53,7 @@ extern const size_t modinfo_attrs_count; /* Provided by the linker */ extern const struct kernel_symbol __start___ksymtab[]; extern const struct kernel_symbol __stop___ksymtab[]; -extern const struct kernel_symbol __start___ksymtab_gpl[]; -extern const struct kernel_symbol __stop___ksymtab_gpl[]; extern const u32 __start___kcrctab[]; -extern const u32 __start___kcrctab_gpl[]; extern const u8 __start___kflagstab[]; #define KMOD_PATH_LEN 256 diff --git a/kernel/module/main.c b/kernel/module/main.c index c243d6b79cdd..c4f768953516 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -1495,29 +1495,17 @@ EXPORT_SYMBOL_GPL(__symbol_get); */ static int verify_exported_symbols(struct module *mod) { - unsigned int i; const struct kernel_symbol *s; - struct { - const struct kernel_symbol *sym; - unsigned int num; - } arr[] = { - { mod->syms, mod->num_syms }, - { mod->gpl_syms, mod->num_gpl_syms }, - }; - - for (i = 0; i < ARRAY_SIZE(arr); i++) { - for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { - struct find_symbol_arg fsa = { - .name = kernel_symbol_name(s), - .gplok = true, - }; - if (find_symbol(&fsa)) { - pr_err("%s: exports duplicate symbol %s" - " (owned by %s)\n", - mod->name, kernel_symbol_name(s), - module_name(fsa.owner)); - return -ENOEXEC; - } + for (s = mod->syms; s < mod->syms + mod->num_syms; s++) { + struct find_symbol_arg fsa = { + .name = kernel_symbol_name(s), + .gplok = true, + }; + if (find_symbol(&fsa)) { + pr_err("%s: exports duplicate symbol %s (owned by %s)\n", + mod->name, kernel_symbol_name(s), + module_name(fsa.owner)); + return -ENOEXEC; } } return 0; @@ -2675,12 +2663,15 @@ static int find_module_sections(struct module *mod, struct load_info *info) mod->syms = section_objs(info, "__ksymtab", sizeof(*mod->syms), &mod->num_syms); mod->crcs = section_addr(info, "__kcrctab"); - mod->gpl_syms = section_objs(info, "__ksymtab_gpl", - sizeof(*mod->gpl_syms), - &mod->num_gpl_syms); - mod->gpl_crcs = section_addr(info, "__kcrctab_gpl"); mod->flagstab = section_addr(info, "__kflagstab"); + if (section_addr(info, "__ksymtab_gpl")) + pr_warn("%s: ignoring obsolete section __ksymtab_gpl\n", + mod->name); + if (section_addr(info, "__kcrctab_gpl")) + pr_warn("%s: ignoring obsolete section __kcrctab_gpl\n", + mod->name); + #ifdef CONFIG_CONSTRUCTORS mod->ctors = section_objs(info, ".ctors", sizeof(*mod->ctors), &mod->num_ctors); @@ -2890,8 +2881,7 @@ static int check_export_symbol_sections(struct module *mod) return -ENOEXEC; } #ifdef CONFIG_MODVERSIONS - if ((mod->num_syms && !mod->crcs) || - (mod->num_gpl_syms && !mod->gpl_crcs)) { + if (mod->num_syms && !mod->crcs) { return try_to_force_load(mod, "no versions for exported symbols"); } -- cgit v1.2.3