* [PATCH 01/10] define kernel symbol flags
2025-08-29 10:54 [RFC PATCH 00/10] scalable symbol flags with __kflagstab Siddharth Nayyar
@ 2025-08-29 10:54 ` Siddharth Nayyar
2025-08-29 10:54 ` [PATCH 02/10] linker: add kflagstab section to vmlinux and modules Siddharth Nayyar
` (9 subsequent siblings)
10 siblings, 0 replies; 22+ messages in thread
From: Siddharth Nayyar @ 2025-08-29 10:54 UTC (permalink / raw)
To: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen
Cc: Nicolas Schier, Petr Pavlu, Arnd Bergmann, linux-kbuild,
linux-arch, linux-modules, linux-kernel, Siddharth Nayyar
Symbol flags is an enumeration used to represent flags as a bitset, for
example a flag to tell if a symbols GPL only.
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
include/linux/module_symbol.h | 5 +++++
1 file changed, 5 insertions(+)
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)
{
--
2.51.0.338.gd7d06c2dae-goog
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH 02/10] linker: add kflagstab section to vmlinux and modules
2025-08-29 10:54 [RFC PATCH 00/10] scalable symbol flags with __kflagstab Siddharth Nayyar
2025-08-29 10:54 ` [PATCH 01/10] define kernel symbol flags Siddharth Nayyar
@ 2025-08-29 10:54 ` Siddharth Nayyar
2025-08-29 10:54 ` [PATCH 03/10] modpost: create entries for kflagstab Siddharth Nayyar
` (8 subsequent siblings)
10 siblings, 0 replies; 22+ messages in thread
From: Siddharth Nayyar @ 2025-08-29 10:54 UTC (permalink / raw)
To: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen
Cc: Nicolas Schier, Petr Pavlu, Arnd Bergmann, linux-kbuild,
linux-arch, linux-modules, linux-kernel, Siddharth Nayyar
This section will contain read-only kernel symbol flag values in the
form of a 8-bit bitset.
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
include/asm-generic/vmlinux.lds.h | 7 +++++++
scripts/module.lds.S | 1 +
2 files changed, 8 insertions(+)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index ae2d2359b79e..310e2de56211 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -518,6 +518,13 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
__stop___kcrctab_gpl = .; \
} \
\
+ /* Kernel symbol flags table */ \
+ __kflagstab : AT(ADDR(__kflagstab) - LOAD_OFFSET) { \
+ __start___kflagstab = .; \
+ KEEP(*(SORT(___kflagstab+*))) \
+ __stop___kflagstab = .; \
+ } \
+ \
/* Kernel symbol table: strings */ \
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
*(__ksymtab_strings) \
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index ee79c41059f3..9a8a3b6d1569 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -23,6 +23,7 @@ SECTIONS {
__ksymtab_gpl 0 : ALIGN(8) { *(SORT(___ksymtab_gpl+*)) }
__kcrctab 0 : ALIGN(4) { *(SORT(___kcrctab+*)) }
__kcrctab_gpl 0 : ALIGN(4) { *(SORT(___kcrctab_gpl+*)) }
+ __kflagstab 0 : ALIGN(1) { *(SORT(___kflagstab+*)) }
.ctors 0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) }
.init_array 0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) }
--
2.51.0.338.gd7d06c2dae-goog
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH 03/10] modpost: create entries for kflagstab
2025-08-29 10:54 [RFC PATCH 00/10] scalable symbol flags with __kflagstab Siddharth Nayyar
2025-08-29 10:54 ` [PATCH 01/10] define kernel symbol flags Siddharth Nayyar
2025-08-29 10:54 ` [PATCH 02/10] linker: add kflagstab section to vmlinux and modules Siddharth Nayyar
@ 2025-08-29 10:54 ` Siddharth Nayyar
2025-08-29 10:54 ` [PATCH 04/10] module loader: use kflagstab instead of *_gpl sections Siddharth Nayyar
` (7 subsequent siblings)
10 siblings, 0 replies; 22+ messages in thread
From: Siddharth Nayyar @ 2025-08-29 10:54 UTC (permalink / raw)
To: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen
Cc: Nicolas Schier, Petr Pavlu, Arnd Bergmann, linux-kbuild,
linux-arch, linux-modules, linux-kernel, Siddharth Nayyar
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
include/linux/export-internal.h | 7 +++++++
scripts/mod/modpost.c | 8 ++++++++
2 files changed, 15 insertions(+)
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 5ca7c268294e..f5ce7aeed52d 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)
{
@@ -1865,6 +1870,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)
--
2.51.0.338.gd7d06c2dae-goog
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH 04/10] module loader: use kflagstab instead of *_gpl sections
2025-08-29 10:54 [RFC PATCH 00/10] scalable symbol flags with __kflagstab Siddharth Nayyar
` (2 preceding siblings ...)
2025-08-29 10:54 ` [PATCH 03/10] modpost: create entries for kflagstab Siddharth Nayyar
@ 2025-08-29 10:54 ` Siddharth Nayyar
2025-10-08 13:19 ` Petr Pavlu
2025-08-29 10:54 ` [PATCH 05/10] modpost: put all exported symbols in ksymtab section Siddharth Nayyar
` (6 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: Siddharth Nayyar @ 2025-08-29 10:54 UTC (permalink / raw)
To: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen
Cc: Nicolas Schier, Petr Pavlu, Arnd Bergmann, linux-kbuild,
linux-arch, linux-modules, linux-kernel, Siddharth Nayyar
Read __kflagstab section for vmlinux and modules to determine whether
kernel symbols are GPL only.
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
include/linux/module.h | 1 +
kernel/module/internal.h | 1 +
kernel/module/main.c | 47 ++++++++++++++++++++--------------------
3 files changed, 25 insertions(+), 24 deletions(-)
diff --git a/include/linux/module.h b/include/linux/module.h
index 3319a5269d28..9ba6ce433ac3 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -415,6 +415,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 c66b26184936..400d59a7f44b 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -11,6 +11,7 @@
#include <linux/extable.h>
#include <linux/moduleloader.h>
#include <linux/module_signature.h>
+#include <linux/module_symbol.h>
#include <linux/trace_events.h>
#include <linux/init.h>
#include <linux/kallsyms.h>
@@ -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);
@@ -2607,6 +2605,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",
--
2.51.0.338.gd7d06c2dae-goog
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH 04/10] module loader: use kflagstab instead of *_gpl sections
2025-08-29 10:54 ` [PATCH 04/10] module loader: use kflagstab instead of *_gpl sections Siddharth Nayyar
@ 2025-10-08 13:19 ` Petr Pavlu
0 siblings, 0 replies; 22+ messages in thread
From: Petr Pavlu @ 2025-10-08 13:19 UTC (permalink / raw)
To: Siddharth Nayyar
Cc: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen,
Nicolas Schier, Arnd Bergmann, linux-kbuild, linux-arch,
linux-modules, linux-kernel
On 8/29/25 12:54 PM, Siddharth Nayyar wrote:
> Read __kflagstab section for vmlinux and modules to determine whether
> kernel symbols are GPL only.
>
> Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
> ---
> [...]
> @@ -2607,6 +2605,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",
The module loader should always at least get through the signature and
blacklist checks without crashing due to a corrupted ELF file. After
that point, the module content is to be trusted, but we try to error out
for most issues that would cause problems later on.
For __kflagstab, I believe it would be useful to check that the section
is present to prevent the code from potentially crashing due to a NULL
dereference deep in find_exported_symbol_in_section(). You can rename
check_export_symbol_versions() to check_export_symbol_sections() and add
the following:
if (mod->num_syms && !mod->flagstab) {
pr_err("%s: no flags for exported symbols\n", mod->name);
return -ENOEXEC;
}
--
Thanks,
Petr
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 05/10] modpost: put all exported symbols in ksymtab section
2025-08-29 10:54 [RFC PATCH 00/10] scalable symbol flags with __kflagstab Siddharth Nayyar
` (3 preceding siblings ...)
2025-08-29 10:54 ` [PATCH 04/10] module loader: use kflagstab instead of *_gpl sections Siddharth Nayyar
@ 2025-08-29 10:54 ` Siddharth Nayyar
2025-08-29 10:54 ` [PATCH 06/10] module loader: remove references of *_gpl sections Siddharth Nayyar
` (5 subsequent siblings)
10 siblings, 0 replies; 22+ messages in thread
From: Siddharth Nayyar @ 2025-08-29 10:54 UTC (permalink / raw)
To: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen
Cc: Nicolas Schier, Petr Pavlu, Arnd Bergmann, linux-kbuild,
linux-arch, linux-modules, linux-kernel, Siddharth Nayyar
Since the modules loader determines whether an exported symbol is GPL
only from the kflagstab section data, modpost can put all symbols in the
regular ksymtab and stop using the *_gpl versions of the ksymtab and
kcrctab.
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
include/linux/export-internal.h | 21 +++++++++++----------
scripts/mod/modpost.c | 8 ++++----
2 files changed, 15 insertions(+), 14 deletions(-)
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/scripts/mod/modpost.c b/scripts/mod/modpost.c
index f5ce7aeed52d..8936db84779b 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1867,9 +1867,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));
@@ -1890,8 +1890,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);
}
}
--
2.51.0.338.gd7d06c2dae-goog
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH 06/10] module loader: remove references of *_gpl sections
2025-08-29 10:54 [RFC PATCH 00/10] scalable symbol flags with __kflagstab Siddharth Nayyar
` (4 preceding siblings ...)
2025-08-29 10:54 ` [PATCH 05/10] modpost: put all exported symbols in ksymtab section Siddharth Nayyar
@ 2025-08-29 10:54 ` Siddharth Nayyar
2025-10-08 13:22 ` Petr Pavlu
2025-08-29 10:54 ` [PATCH 07/10] linker: remove *_gpl sections from vmlinux and modules Siddharth Nayyar
` (4 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: Siddharth Nayyar @ 2025-08-29 10:54 UTC (permalink / raw)
To: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen
Cc: Nicolas Schier, Petr Pavlu, Arnd Bergmann, linux-kbuild,
linux-arch, linux-modules, linux-kernel, Siddharth Nayyar
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.
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
include/linux/module.h | 3 ---
kernel/module/internal.h | 3 ---
kernel/module/main.c | 40 ++++++++++++----------------------------
3 files changed, 12 insertions(+), 34 deletions(-)
diff --git a/include/linux/module.h b/include/linux/module.h
index 9ba6ce433ac3..1a9c41318e22 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -431,9 +431,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 400d59a7f44b..4437c2a451ea 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -1464,29 +1464,18 @@ 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;
@@ -2601,10 +2590,6 @@ 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");
#ifdef CONFIG_CONSTRUCTORS
@@ -2812,8 +2797,7 @@ static int move_module(struct module *mod, struct load_info *info)
static int check_export_symbol_versions(struct module *mod)
{
#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");
}
--
2.51.0.338.gd7d06c2dae-goog
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH 06/10] module loader: remove references of *_gpl sections
2025-08-29 10:54 ` [PATCH 06/10] module loader: remove references of *_gpl sections Siddharth Nayyar
@ 2025-10-08 13:22 ` Petr Pavlu
0 siblings, 0 replies; 22+ messages in thread
From: Petr Pavlu @ 2025-10-08 13:22 UTC (permalink / raw)
To: Siddharth Nayyar
Cc: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen,
Nicolas Schier, Arnd Bergmann, linux-kbuild, linux-arch,
linux-modules, linux-kernel
On 8/29/25 12:54 PM, Siddharth Nayyar wrote:
> 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.
>
> Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
> ---
> [...]
> @@ -2601,10 +2590,6 @@ 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");
>
I suggest adding a check that the loaded module doesn't contain
a __ksymtab_gpl or __kcrctab_gpl section, similarly how the function
later checks if the old __obsparm section isn't present. Something like:
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);
--
Thanks,
Petr
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 07/10] linker: remove *_gpl sections from vmlinux and modules
2025-08-29 10:54 [RFC PATCH 00/10] scalable symbol flags with __kflagstab Siddharth Nayyar
` (5 preceding siblings ...)
2025-08-29 10:54 ` [PATCH 06/10] module loader: remove references of *_gpl sections Siddharth Nayyar
@ 2025-08-29 10:54 ` Siddharth Nayyar
2025-08-29 10:54 ` [PATCH 08/10] remove references to *_gpl sections in documentation Siddharth Nayyar
` (3 subsequent siblings)
10 siblings, 0 replies; 22+ messages in thread
From: Siddharth Nayyar @ 2025-08-29 10:54 UTC (permalink / raw)
To: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen
Cc: Nicolas Schier, Petr Pavlu, Arnd Bergmann, linux-kbuild,
linux-arch, linux-modules, linux-kernel, Siddharth Nayyar
These sections are not used anymore and can be removed from vmlinux and
modules.
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
include/asm-generic/vmlinux.lds.h | 18 ++----------------
scripts/module.lds.S | 2 --
2 files changed, 2 insertions(+), 18 deletions(-)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 310e2de56211..6490b93d23b1 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -490,34 +490,20 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
\
PRINTK_INDEX \
\
- /* Kernel symbol table: Normal symbols */ \
+ /* Kernel symbol table */ \
__ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \
__start___ksymtab = .; \
KEEP(*(SORT(___ksymtab+*))) \
__stop___ksymtab = .; \
} \
\
- /* Kernel symbol table: GPL-only symbols */ \
- __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \
- __start___ksymtab_gpl = .; \
- KEEP(*(SORT(___ksymtab_gpl+*))) \
- __stop___ksymtab_gpl = .; \
- } \
- \
- /* Kernel symbol table: Normal symbols */ \
+ /* Kernel symbol CRC table */ \
__kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \
__start___kcrctab = .; \
KEEP(*(SORT(___kcrctab+*))) \
__stop___kcrctab = .; \
} \
\
- /* Kernel symbol table: GPL-only symbols */ \
- __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \
- __start___kcrctab_gpl = .; \
- KEEP(*(SORT(___kcrctab_gpl+*))) \
- __stop___kcrctab_gpl = .; \
- } \
- \
/* Kernel symbol flags table */ \
__kflagstab : AT(ADDR(__kflagstab) - LOAD_OFFSET) { \
__start___kflagstab = .; \
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 9a8a3b6d1569..1841a43d8771 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -20,9 +20,7 @@ SECTIONS {
}
__ksymtab 0 : ALIGN(8) { *(SORT(___ksymtab+*)) }
- __ksymtab_gpl 0 : ALIGN(8) { *(SORT(___ksymtab_gpl+*)) }
__kcrctab 0 : ALIGN(4) { *(SORT(___kcrctab+*)) }
- __kcrctab_gpl 0 : ALIGN(4) { *(SORT(___kcrctab_gpl+*)) }
__kflagstab 0 : ALIGN(1) { *(SORT(___kflagstab+*)) }
.ctors 0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) }
--
2.51.0.338.gd7d06c2dae-goog
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH 08/10] remove references to *_gpl sections in documentation
2025-08-29 10:54 [RFC PATCH 00/10] scalable symbol flags with __kflagstab Siddharth Nayyar
` (6 preceding siblings ...)
2025-08-29 10:54 ` [PATCH 07/10] linker: remove *_gpl sections from vmlinux and modules Siddharth Nayyar
@ 2025-08-29 10:54 ` Siddharth Nayyar
2025-10-08 13:24 ` Petr Pavlu
2025-08-29 10:54 ` [PATCH 09/10] modpost: add symbol import protection flag to kflagstab Siddharth Nayyar
` (2 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: Siddharth Nayyar @ 2025-08-29 10:54 UTC (permalink / raw)
To: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen
Cc: Nicolas Schier, Petr Pavlu, Arnd Bergmann, linux-kbuild,
linux-arch, linux-modules, linux-kernel, Siddharth Nayyar
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
Documentation/kbuild/modules.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst
index d0703605bfa4..f2022fa2342f 100644
--- a/Documentation/kbuild/modules.rst
+++ b/Documentation/kbuild/modules.rst
@@ -426,11 +426,11 @@ Symbols From the Kernel (vmlinux + modules)
Version Information Formats
---------------------------
- Exported symbols have information stored in __ksymtab or __ksymtab_gpl
- sections. Symbol names and namespaces are stored in __ksymtab_strings,
+ Exported symbols have information stored in the __ksymtab section.
+ Symbol names and namespaces are stored in __ksymtab_strings section,
using a format similar to the string table used for ELF. If
CONFIG_MODVERSIONS is enabled, the CRCs corresponding to exported
- symbols will be added to the __kcrctab or __kcrctab_gpl.
+ symbols will be added to the __kcrctab section.
If CONFIG_BASIC_MODVERSIONS is enabled (default with
CONFIG_MODVERSIONS), imported symbols will have their symbol name and
--
2.51.0.338.gd7d06c2dae-goog
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH 08/10] remove references to *_gpl sections in documentation
2025-08-29 10:54 ` [PATCH 08/10] remove references to *_gpl sections in documentation Siddharth Nayyar
@ 2025-10-08 13:24 ` Petr Pavlu
0 siblings, 0 replies; 22+ messages in thread
From: Petr Pavlu @ 2025-10-08 13:24 UTC (permalink / raw)
To: Siddharth Nayyar
Cc: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen,
Nicolas Schier, Arnd Bergmann, linux-kbuild, linux-arch,
linux-modules, linux-kernel
On 8/29/25 12:54 PM, Siddharth Nayyar wrote:
> Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
> ---
> Documentation/kbuild/modules.rst | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst
> index d0703605bfa4..f2022fa2342f 100644
> --- a/Documentation/kbuild/modules.rst
> +++ b/Documentation/kbuild/modules.rst
> @@ -426,11 +426,11 @@ Symbols From the Kernel (vmlinux + modules)
> Version Information Formats
> ---------------------------
>
> - Exported symbols have information stored in __ksymtab or __ksymtab_gpl
> - sections. Symbol names and namespaces are stored in __ksymtab_strings,
> + Exported symbols have information stored in the __ksymtab section.
> + Symbol names and namespaces are stored in __ksymtab_strings section,
> using a format similar to the string table used for ELF. If
> CONFIG_MODVERSIONS is enabled, the CRCs corresponding to exported
> - symbols will be added to the __kcrctab or __kcrctab_gpl.
> + symbols will be added to the __kcrctab section.
>
> If CONFIG_BASIC_MODVERSIONS is enabled (default with
> CONFIG_MODVERSIONS), imported symbols will have their symbol name and
Nit: I realize this part of the document primarily discusses sections
related to modversions, but I think it would be good to briefly mention
also the existence of the __kflagstab section. The first sentence could
say:
Exported symbols have information stored in the __ksymtab and
__kflagstab sections.
--
Thanks,
Petr
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 09/10] modpost: add symbol import protection flag to kflagstab
2025-08-29 10:54 [RFC PATCH 00/10] scalable symbol flags with __kflagstab Siddharth Nayyar
` (7 preceding siblings ...)
2025-08-29 10:54 ` [PATCH 08/10] remove references to *_gpl sections in documentation Siddharth Nayyar
@ 2025-08-29 10:54 ` Siddharth Nayyar
2025-10-08 13:35 ` Petr Pavlu
2025-08-29 10:54 ` [PATCH 10/10] module loader: enforce symbol import protection Siddharth Nayyar
2025-09-01 12:27 ` [RFC PATCH 00/10] scalable symbol flags with __kflagstab Petr Pavlu
10 siblings, 1 reply; 22+ messages in thread
From: Siddharth Nayyar @ 2025-08-29 10:54 UTC (permalink / raw)
To: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen
Cc: Nicolas Schier, Petr Pavlu, Arnd Bergmann, linux-kbuild,
linux-arch, linux-modules, linux-kernel, Siddharth Nayyar
When the unused exports whitelist is provided, the symbol protection bit
is set for symbols not present in the unused exports whitelist.
The flag will be used in the following commit to prevent unsigned
modules from the using symbols other than those explicitly declared by
the such modules ahead of time.
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
include/linux/module_symbol.h | 3 ++-
scripts/mod/modpost.c | 13 +++++++++++--
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/include/linux/module_symbol.h b/include/linux/module_symbol.h
index 574609aced99..96fe3f4d7424 100644
--- a/include/linux/module_symbol.h
+++ b/include/linux/module_symbol.h
@@ -3,8 +3,9 @@
#define _LINUX_MODULE_SYMBOL_H
/* Kernel symbol flags bitset. */
-enum ksym_flags {
+enum symbol_flags {
KSYM_FLAG_GPL_ONLY = 1 << 0,
+ KSYM_FLAG_PROTECTED = 1 << 1,
};
/* This ignores the intensely annoying "mapping symbols" found in ELF files. */
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 8936db84779b..8d360bab50d6 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -61,6 +61,9 @@ static bool extra_warn;
bool target_is_big_endian;
bool host_is_big_endian;
+/* Are symbols protected against being used by unsigned modules? */
+static bool default_symbol_protected_status;
+
/*
* Cut off the warnings when there are too many. This typically occurs when
* vmlinux is missing. ('make modules' without building vmlinux.)
@@ -225,6 +228,7 @@ struct symbol {
bool is_func;
bool is_gpl_only; /* exported by EXPORT_SYMBOL_GPL */
bool used; /* there exists a user of this symbol */
+ bool protected; /* this symbol cannot be used by unsigned modules */
char name[];
};
@@ -246,7 +250,8 @@ static struct symbol *alloc_symbol(const char *name)
static uint8_t get_symbol_flags(const struct symbol *sym)
{
- return sym->is_gpl_only ? KSYM_FLAG_GPL_ONLY : 0;
+ return (sym->is_gpl_only ? KSYM_FLAG_GPL_ONLY : 0) |
+ (sym->protected ? KSYM_FLAG_PROTECTED : 0);
}
/* For the hash of exported symbols */
@@ -370,6 +375,7 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod,
s->namespace = xstrdup(namespace);
list_add_tail(&s->list, &mod->exported_symbols);
hash_add_symbol(s);
+ s->protected = default_symbol_protected_status;
return s;
}
@@ -1785,8 +1791,10 @@ static void handle_white_list_exports(const char *white_list)
while ((name = strsep(&p, "\n"))) {
struct symbol *sym = find_symbol(name);
- if (sym)
+ if (sym) {
sym->used = true;
+ sym->protected = false;
+ }
}
free(buf);
@@ -2294,6 +2302,7 @@ int main(int argc, char **argv)
break;
case 'u':
unused_exports_white_list = optarg;
+ default_symbol_protected_status = true;
break;
case 'W':
extra_warn = true;
--
2.51.0.338.gd7d06c2dae-goog
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH 09/10] modpost: add symbol import protection flag to kflagstab
2025-08-29 10:54 ` [PATCH 09/10] modpost: add symbol import protection flag to kflagstab Siddharth Nayyar
@ 2025-10-08 13:35 ` Petr Pavlu
0 siblings, 0 replies; 22+ messages in thread
From: Petr Pavlu @ 2025-10-08 13:35 UTC (permalink / raw)
To: Siddharth Nayyar
Cc: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen,
Nicolas Schier, Arnd Bergmann, linux-kbuild, linux-arch,
linux-modules, linux-kernel
On 8/29/25 12:54 PM, Siddharth Nayyar wrote:
> When the unused exports whitelist is provided, the symbol protection bit
> is set for symbols not present in the unused exports whitelist.
>
> The flag will be used in the following commit to prevent unsigned
> modules from the using symbols other than those explicitly declared by
> the such modules ahead of time.
>
> Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
> ---
> [...]
> diff --git a/include/linux/module_symbol.h b/include/linux/module_symbol.h
> index 574609aced99..96fe3f4d7424 100644
> --- a/include/linux/module_symbol.h
> +++ b/include/linux/module_symbol.h
> @@ -3,8 +3,9 @@
> #define _LINUX_MODULE_SYMBOL_H
>
> /* Kernel symbol flags bitset. */
> -enum ksym_flags {
> +enum symbol_flags {
> KSYM_FLAG_GPL_ONLY = 1 << 0,
> + KSYM_FLAG_PROTECTED = 1 << 1,
> };
>
Nit: The ksym_flags enum is added in patch #1. If you prefer a different
name, you can change it in that patch.
--
Thanks,
Petr
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 10/10] module loader: enforce symbol import protection
2025-08-29 10:54 [RFC PATCH 00/10] scalable symbol flags with __kflagstab Siddharth Nayyar
` (8 preceding siblings ...)
2025-08-29 10:54 ` [PATCH 09/10] modpost: add symbol import protection flag to kflagstab Siddharth Nayyar
@ 2025-08-29 10:54 ` Siddharth Nayyar
2025-10-08 15:35 ` Petr Pavlu
2025-09-01 12:27 ` [RFC PATCH 00/10] scalable symbol flags with __kflagstab Petr Pavlu
10 siblings, 1 reply; 22+ messages in thread
From: Siddharth Nayyar @ 2025-08-29 10:54 UTC (permalink / raw)
To: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen
Cc: Nicolas Schier, Petr Pavlu, Arnd Bergmann, linux-kbuild,
linux-arch, linux-modules, linux-kernel, Siddharth Nayyar
The module loader will reject unsigned modules from loading if such a
module attempts to import a symbol which has the import protection bit
set in the kflagstab entry for the symbol.
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
kernel/module/internal.h | 1 +
kernel/module/main.c | 14 ++++++++++++--
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index 061161cc79d9..98faaf8900aa 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -108,6 +108,7 @@ struct find_symbol_arg {
const u32 *crc;
const struct kernel_symbol *sym;
enum mod_license license;
+ bool is_protected;
};
/* modules using other modules */
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 4437c2a451ea..ece074a6ba7b 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -380,6 +380,7 @@ static bool find_exported_symbol_in_section(const struct symsearch *syms,
fsa->crc = symversion(syms->crcs, sym - syms->start);
fsa->sym = sym;
fsa->license = (sym_flags & KSYM_FLAG_GPL_ONLY) ? GPL_ONLY : NOT_GPL_ONLY;
+ fsa->is_protected = sym_flags & KSYM_FLAG_PROTECTED;
return true;
}
@@ -1273,6 +1274,11 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
goto getname;
}
+ if (fsa.is_protected && !mod->sig_ok) {
+ fsa.sym = ERR_PTR(-EACCES);
+ goto getname;
+ }
+
getname:
/* We must make copy under the lock if we failed to get ref. */
strscpy(ownername, module_name(fsa.owner), MODULE_NAME_LEN);
@@ -1550,8 +1556,12 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
break;
ret = PTR_ERR(ksym) ?: -ENOENT;
- pr_warn("%s: Unknown symbol %s (err %d)\n",
- mod->name, name, ret);
+ if (ret == -EACCES)
+ pr_warn("%s: Protected symbol %s (err %d)\n",
+ mod->name, name, ret);
+ else
+ pr_warn("%s: Unknown symbol %s (err %d)\n",
+ mod->name, name, ret);
break;
default:
--
2.51.0.338.gd7d06c2dae-goog
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH 10/10] module loader: enforce symbol import protection
2025-08-29 10:54 ` [PATCH 10/10] module loader: enforce symbol import protection Siddharth Nayyar
@ 2025-10-08 15:35 ` Petr Pavlu
0 siblings, 0 replies; 22+ messages in thread
From: Petr Pavlu @ 2025-10-08 15:35 UTC (permalink / raw)
To: Siddharth Nayyar
Cc: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen,
Nicolas Schier, Arnd Bergmann, linux-kbuild, linux-arch,
linux-modules, linux-kernel
On 8/29/25 12:54 PM, Siddharth Nayyar wrote:
> The module loader will reject unsigned modules from loading if such a
> module attempts to import a symbol which has the import protection bit
> set in the kflagstab entry for the symbol.
>
> Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
> ---
> [...]
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 4437c2a451ea..ece074a6ba7b 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -380,6 +380,7 @@ static bool find_exported_symbol_in_section(const struct symsearch *syms,
> fsa->crc = symversion(syms->crcs, sym - syms->start);
> fsa->sym = sym;
> fsa->license = (sym_flags & KSYM_FLAG_GPL_ONLY) ? GPL_ONLY : NOT_GPL_ONLY;
> + fsa->is_protected = sym_flags & KSYM_FLAG_PROTECTED;
>
> return true;
> }
> @@ -1273,6 +1274,11 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
> goto getname;
> }
>
> + if (fsa.is_protected && !mod->sig_ok) {
> + fsa.sym = ERR_PTR(-EACCES);
> + goto getname;
> + }
> +
> getname:
> /* We must make copy under the lock if we failed to get ref. */
> strscpy(ownername, module_name(fsa.owner), MODULE_NAME_LEN);
The is_protected check should be moved before the ref_module() call.
Adding a reference to another module should be always the last step,
after all symbol checks have been performed.
> @@ -1550,8 +1556,12 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
> break;
>
> ret = PTR_ERR(ksym) ?: -ENOENT;
> - pr_warn("%s: Unknown symbol %s (err %d)\n",
> - mod->name, name, ret);
> + if (ret == -EACCES)
> + pr_warn("%s: Protected symbol %s (err %d)\n",
> + mod->name, name, ret);
> + else
> + pr_warn("%s: Unknown symbol %s (err %d)\n",
> + mod->name, name, ret);
> break;
>
> default:
I suggest moving the error message about the symbol being protected down
into resolve_symbol(), at the point where this issue is detected. This
approach is generally used for other checks, such as the CRC or
namespace check. Additionally, I think it would make sense to change the
current "Unknown symbol" warning here to "Unresolved symbol" to be more
accurate.
--
Thanks,
Petr
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH 00/10] scalable symbol flags with __kflagstab
2025-08-29 10:54 [RFC PATCH 00/10] scalable symbol flags with __kflagstab Siddharth Nayyar
` (9 preceding siblings ...)
2025-08-29 10:54 ` [PATCH 10/10] module loader: enforce symbol import protection Siddharth Nayyar
@ 2025-09-01 12:27 ` Petr Pavlu
2025-09-03 23:28 ` Sid Nayyar
10 siblings, 1 reply; 22+ messages in thread
From: Petr Pavlu @ 2025-09-01 12:27 UTC (permalink / raw)
To: Siddharth Nayyar
Cc: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen,
Nicolas Schier, Arnd Bergmann, linux-kbuild, linux-arch,
linux-modules, linux-kernel
On 8/29/25 12:54 PM, Siddharth Nayyar wrote:
> Hi everyone,
>
> This patch series proposes a new, scalable mechanism to represent
> boolean flags for exported kernel symbols.
>
> Problem Statement:
>
> 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.
>
> Proposed Solution:
>
> This series introduces a __kflagstab section to store symbol flags in a
> dedicated data structure, similar to how CRCs are handled in the
> __kcrctab.
>
> The flags for a given symbol in __kflagstab will be located at the same
> index as the symbol's entry in __ksymtab and its CRC in __kcrctab. This
> design decouples the flags from the symbol table itself, allowing us to
> maintain a single, sorted __ksymtab. As a result, the symbol search
> remains an efficient, single lookup, regardless of the number of flags
> we add in the future.
Merging __ksymtab and __ksymtab_gpl into a single section looks ok to
me, and similarly for __kcrctab and __kcrtab_gpl. The __ksymtab_gpl
support originally comes from commit 3344ea3ad4 ("[PATCH] MODULE_LICENSE
and EXPORT_SYMBOL_GPL support") [1], where it was named __gpl_ksymtab.
The commit doesn't mention why the implementation opts for using
a separate section, but I suspect it was designed this way to reduce
memory/disk usage.
A question is whether the symbol flags should be stored in a new
__kflagstab section, instead of adding a flag member to the existing
__ksymtab. As far as I'm aware, no userspace tool (particularly kmod)
uses the __ksymtab data, so we are free to update its format.
Note that I believe that __kcrctab/__kcrtab_gpl is a separate section
because the CRC data is available only if CONFIG_MODVERSIONS=y.
Including the flags as part of __ksymtab would be obviously a simpler
schema. On the other hand, an entry in __ksymtab has in the worst case
a size of 24 bytes with an 8-byte alignment requirement. This means that
adding a flag to it would require additional 8 bytes per symbol.
>
> The motivation for this change comes from the Android kernel, which uses
> an additional symbol flag to restrict the use of certain exported
> symbols by unsigned modules, thereby enhancing kernel security. This
> __kflagstab can be implemented as a bitmap to efficiently manage which
> symbols are available for general use versus those restricted to signed
> modules only.
I think it would be useful to explain in more detail how this protected
schema is used in practice and what problem it solves. Who is allowed to
provide these limited unsigned modules and if the concern is kernel
security, can't you enforce the use of only signed modules?
[1] https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git/commit/?id=3344ea3ad4b7c302c846a680dbaeedf96ed45c02
--
Thanks,
Petr
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [RFC PATCH 00/10] scalable symbol flags with __kflagstab
2025-09-01 12:27 ` [RFC PATCH 00/10] scalable symbol flags with __kflagstab Petr Pavlu
@ 2025-09-03 23:28 ` Sid Nayyar
2025-09-08 10:09 ` Petr Pavlu
0 siblings, 1 reply; 22+ messages in thread
From: Sid Nayyar @ 2025-09-03 23:28 UTC (permalink / raw)
To: Petr Pavlu
Cc: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen,
Nicolas Schier, Arnd Bergmann, linux-kbuild, linux-arch,
linux-modules, linux-kernel, Giuliano Procida,
Matthias Männich
On Mon, Sep 1, 2025 at 1:27 PM Petr Pavlu <petr.pavlu@suse.com> wrote:
> Merging __ksymtab and __ksymtab_gpl into a single section looks ok to
> me, and similarly for __kcrctab and __kcrtab_gpl. The __ksymtab_gpl
> support originally comes from commit 3344ea3ad4 ("[PATCH] MODULE_LICENSE
> and EXPORT_SYMBOL_GPL support") [1], where it was named __gpl_ksymtab.
> The commit doesn't mention why the implementation opts for using
> a separate section, but I suspect it was designed this way to reduce
> memory/disk usage.
>
> A question is whether the symbol flags should be stored in a new
> __kflagstab section, instead of adding a flag member to the existing
> __ksymtab. As far as I'm aware, no userspace tool (particularly kmod)
> uses the __ksymtab data, so we are free to update its format.
>
> Note that I believe that __kcrctab/__kcrtab_gpl is a separate section
> because the CRC data is available only if CONFIG_MODVERSIONS=y.
>
> Including the flags as part of __ksymtab would be obviously a simpler
> schema. On the other hand, an entry in __ksymtab has in the worst case
> a size of 24 bytes with an 8-byte alignment requirement. This means that
> adding a flag to it would require additional 8 bytes per symbol.
Thanks for looking into the history of the _gpl split. We also noted
that there were up to five separate arrays at one point.
We explored three approaches to this problem: using the existing
__ksymtab, packing flags as bit-vectors, and the proposed
__kflagstab. We ruled out the bit-vector approach due to its
complexity, which would only save a few bits per symbol. The
__ksymtab approach, while the simplest, was too wasteful of space.
The __kflagstab seems like a good compromise, offering a slight
increase in complexity over the __ksymtab method but requiring only
one extra byte per symbol.
> >
> > The motivation for this change comes from the Android kernel, which uses
> > an additional symbol flag to restrict the use of certain exported
> > symbols by unsigned modules, thereby enhancing kernel security. This
> > __kflagstab can be implemented as a bitmap to efficiently manage which
> > symbols are available for general use versus those restricted to signed
> > modules only.
>
> I think it would be useful to explain in more detail how this protected
> schema is used in practice and what problem it solves. Who is allowed to
> provide these limited unsigned modules and if the concern is kernel
> security, can't you enforce the use of only signed modules?
The Android Common Kernel source is compiled into what we call
GKI (Generic Kernel Image), which consists of a kernel and a
number of modules. We maintain a stable interface (based on CRCs and
types) between the GKI components and vendor-specific modules
(compiled by device manufacturers, e.g., for hardware-specific
drivers) for the lifetime of a given GKI version.
This interface is intentionally restricted to the minimal set of
symbols required by the union of all vendor modules; our partners
declare their requirements in symbol lists. Any additions to these
lists are reviewed to ensure kernel internals are not overly exposed.
For example, we restrict drivers from having the ability to open and
read arbitrary files. This ABI boundary also allows us to evolve
internal kernel types that are not exposed to vendor modules, for
example, when a security fix requires a type to change.
The mechanism we use for this is CONFIG_TRIM_UNUSED_KSYMS and
CONFIG_UNUSED_KSYMS_WHITELIST. This results in a ksymtab
containing two kinds of exported symbols: those explicitly required
by vendors ("vendor-listed") and those only required by GKI modules
("GKI use only").
On top of this, we have implemented symbol import protection
(covered in patches 9/10 and 10/10). This feature prevents vendor
modules from using symbols that are not on the vendor-listed
whitelist. It is built on top of CONFIG_MODULE_SIG. GKI modules are
signed with a specific key, while vendor modules are unsigned and thus
treated as untrusted. This distinction allows signed GKI modules to
use any symbol in the ksymtab, while unsigned vendor modules can only
access the declared subset. This provides a significant layer of
defense and security against potentially exploitable vendor module
code.
Finally, we have implemented symbol export protection, which prevents
a vendor module from impersonating a GKI module by exporting any of
the same symbols. Note that this protection is currently specific to
the Android kernel and is not included in this patch series.
We have several years of experience with older implementations of
these protection mechanisms. The code in this series is a
considerably cleaner and simpler version compared to what has been
shipping in Android kernels since Android 14 (6.1 kernel).
I hope this clarifies the goals of the patch set. Let me know if you
have further questions.
--
Thanks,
Siddharth Nayyar
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [RFC PATCH 00/10] scalable symbol flags with __kflagstab
2025-09-03 23:28 ` Sid Nayyar
@ 2025-09-08 10:09 ` Petr Pavlu
2025-09-15 15:53 ` Sid Nayyar
0 siblings, 1 reply; 22+ messages in thread
From: Petr Pavlu @ 2025-09-08 10:09 UTC (permalink / raw)
To: Sid Nayyar
Cc: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen,
Nicolas Schier, Arnd Bergmann, linux-kbuild, linux-arch,
linux-modules, linux-kernel, Giuliano Procida,
Matthias Männich
On 9/4/25 1:28 AM, Sid Nayyar wrote:
> On Mon, Sep 1, 2025 at 1:27 PM Petr Pavlu <petr.pavlu@suse.com> wrote:
>> Merging __ksymtab and __ksymtab_gpl into a single section looks ok to
>> me, and similarly for __kcrctab and __kcrtab_gpl. The __ksymtab_gpl
>> support originally comes from commit 3344ea3ad4 ("[PATCH] MODULE_LICENSE
>> and EXPORT_SYMBOL_GPL support") [1], where it was named __gpl_ksymtab.
>> The commit doesn't mention why the implementation opts for using
>> a separate section, but I suspect it was designed this way to reduce
>> memory/disk usage.
>>
>> A question is whether the symbol flags should be stored in a new
>> __kflagstab section, instead of adding a flag member to the existing
>> __ksymtab. As far as I'm aware, no userspace tool (particularly kmod)
>> uses the __ksymtab data, so we are free to update its format.
>>
>> Note that I believe that __kcrctab/__kcrtab_gpl is a separate section
>> because the CRC data is available only if CONFIG_MODVERSIONS=y.
>>
>> Including the flags as part of __ksymtab would be obviously a simpler
>> schema. On the other hand, an entry in __ksymtab has in the worst case
>> a size of 24 bytes with an 8-byte alignment requirement. This means that
>> adding a flag to it would require additional 8 bytes per symbol.
>
> Thanks for looking into the history of the _gpl split. We also noted
> that there were up to five separate arrays at one point.
>
> We explored three approaches to this problem: using the existing
> __ksymtab, packing flags as bit-vectors, and the proposed
> __kflagstab. We ruled out the bit-vector approach due to its
> complexity, which would only save a few bits per symbol. The
> __ksymtab approach, while the simplest, was too wasteful of space.
> The __kflagstab seems like a good compromise, offering a slight
> increase in complexity over the __ksymtab method but requiring only
> one extra byte per symbol.
This sounds reasonable to me. Do you have any numbers on hand that would
show the impact of extending __ksymtab?
>
>>>
>>> The motivation for this change comes from the Android kernel, which uses
>>> an additional symbol flag to restrict the use of certain exported
>>> symbols by unsigned modules, thereby enhancing kernel security. This
>>> __kflagstab can be implemented as a bitmap to efficiently manage which
>>> symbols are available for general use versus those restricted to signed
>>> modules only.
>>
>> I think it would be useful to explain in more detail how this protected
>> schema is used in practice and what problem it solves. Who is allowed to
>> provide these limited unsigned modules and if the concern is kernel
>> security, can't you enforce the use of only signed modules?
>
> The Android Common Kernel source is compiled into what we call
> GKI (Generic Kernel Image), which consists of a kernel and a
> number of modules. We maintain a stable interface (based on CRCs and
> types) between the GKI components and vendor-specific modules
> (compiled by device manufacturers, e.g., for hardware-specific
> drivers) for the lifetime of a given GKI version.
>
> This interface is intentionally restricted to the minimal set of
> symbols required by the union of all vendor modules; our partners
> declare their requirements in symbol lists. Any additions to these
> lists are reviewed to ensure kernel internals are not overly exposed.
> For example, we restrict drivers from having the ability to open and
> read arbitrary files. This ABI boundary also allows us to evolve
> internal kernel types that are not exposed to vendor modules, for
> example, when a security fix requires a type to change.
>
> The mechanism we use for this is CONFIG_TRIM_UNUSED_KSYMS and
> CONFIG_UNUSED_KSYMS_WHITELIST. This results in a ksymtab
> containing two kinds of exported symbols: those explicitly required
> by vendors ("vendor-listed") and those only required by GKI modules
> ("GKI use only").
>
> On top of this, we have implemented symbol import protection
> (covered in patches 9/10 and 10/10). This feature prevents vendor
> modules from using symbols that are not on the vendor-listed
> whitelist. It is built on top of CONFIG_MODULE_SIG. GKI modules are
> signed with a specific key, while vendor modules are unsigned and thus
> treated as untrusted. This distinction allows signed GKI modules to
> use any symbol in the ksymtab, while unsigned vendor modules can only
> access the declared subset. This provides a significant layer of
> defense and security against potentially exploitable vendor module
> code.
If I understand correctly, this is similar to the recently introduced
EXPORT_SYMBOL_FOR_MODULES() macro, but with a coarser boundary.
I think that if the goal is to control the kABI scope and limit the use
of certain symbols only to GKI modules, then having the protection
depend on whether the module is signed is somewhat odd. It doesn't give
me much confidence if vendor modules are unsigned in the Android
ecosystem. I would expect that you want to improve this in the long
term.
It would then make more sense to me if the protection was determined by
whether the module is in-tree (the "intree" flag in modinfo) or,
alternatively, if it is signed by a built-in trusted key. I feel this
way the feature could be potentially useful for other distributions that
care about the kABI scope and have ecosystems where vendor modules are
properly signed with some key. However, I'm not sure if this would still
work in your case.
>
> Finally, we have implemented symbol export protection, which prevents
> a vendor module from impersonating a GKI module by exporting any of
> the same symbols. Note that this protection is currently specific to
> the Android kernel and is not included in this patch series.
>
> We have several years of experience with older implementations of
> these protection mechanisms. The code in this series is a
> considerably cleaner and simpler version compared to what has been
> shipping in Android kernels since Android 14 (6.1 kernel).
I agree. I'm not aware of any other distribution that would immediately
need this feature, so it is good if the implementation is kept
reasonably straightforward and doesn't overly complicate the module
loader code.
--
Thanks,
Petr
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [RFC PATCH 00/10] scalable symbol flags with __kflagstab
2025-09-08 10:09 ` Petr Pavlu
@ 2025-09-15 15:53 ` Sid Nayyar
2025-09-22 11:41 ` Petr Pavlu
0 siblings, 1 reply; 22+ messages in thread
From: Sid Nayyar @ 2025-09-15 15:53 UTC (permalink / raw)
To: Petr Pavlu
Cc: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen,
Nicolas Schier, Arnd Bergmann, linux-kbuild, linux-arch,
linux-modules, linux-kernel, Giuliano Procida,
Matthias Männich
On Mon, Sep 8, 2025 at 11:09 AM Petr Pavlu <petr.pavlu@suse.com> wrote:
> This sounds reasonable to me. Do you have any numbers on hand that would
> show the impact of extending __ksymtab?
I did performance analysis for module loading. The kflagstab
optimizes symbol search, which accounts for less than 2% of the
average module load time. Therefore, this change does not translate
into any meaningful gains (or losses) in module loading performance.
On the binary size side, the on-disk size for vmlinux is somewhat
inflated due to extra entries in .symtab and .strtab. Since these
sections are not part of the final Image, the only increase in the
in-memory size of the kernel is for the kflagstab itself. This new
table occupies 1 byte for each symbol in the ksymtab.
> > The Android Common Kernel source is compiled into what we call
> > GKI (Generic Kernel Image), which consists of a kernel and a
> > number of modules. We maintain a stable interface (based on CRCs and
> > types) between the GKI components and vendor-specific modules
> > (compiled by device manufacturers, e.g., for hardware-specific
> > drivers) for the lifetime of a given GKI version.
> >
> > This interface is intentionally restricted to the minimal set of
> > symbols required by the union of all vendor modules; our partners
> > declare their requirements in symbol lists. Any additions to these
> > lists are reviewed to ensure kernel internals are not overly exposed.
> > For example, we restrict drivers from having the ability to open and
> > read arbitrary files. This ABI boundary also allows us to evolve
> > internal kernel types that are not exposed to vendor modules, for
> > example, when a security fix requires a type to change.
> >
> > The mechanism we use for this is CONFIG_TRIM_UNUSED_KSYMS and
> > CONFIG_UNUSED_KSYMS_WHITELIST. This results in a ksymtab
> > containing two kinds of exported symbols: those explicitly required
> > by vendors ("vendor-listed") and those only required by GKI modules
> > ("GKI use only").
> >
> > On top of this, we have implemented symbol import protection
> > (covered in patches 9/10 and 10/10). This feature prevents vendor
> > modules from using symbols that are not on the vendor-listed
> > whitelist. It is built on top of CONFIG_MODULE_SIG. GKI modules are
> > signed with a specific key, while vendor modules are unsigned and thus
> > treated as untrusted. This distinction allows signed GKI modules to
> > use any symbol in the ksymtab, while unsigned vendor modules can only
> > access the declared subset. This provides a significant layer of
> > defense and security against potentially exploitable vendor module
> > code.
>
> If I understand correctly, this is similar to the recently introduced
> EXPORT_SYMBOL_FOR_MODULES() macro, but with a coarser boundary.
>
> I think that if the goal is to control the kABI scope and limit the use
> of certain symbols only to GKI modules, then having the protection
> depend on whether the module is signed is somewhat odd. It doesn't give
> me much confidence if vendor modules are unsigned in the Android
> ecosystem. I would expect that you want to improve this in the long
> term.
GKI modules are the only modules built in the same Kbuild as the
kernel image, which Google builds and provides to partners. In
contrast, vendor modules are built and packaged entirely by partners.
Google signs GKI modules with ephemeral keys. Since partners do
not have these keys, vendor modules are treated as unsigned by
the kernel.
To ensure the authenticity of these unsigned modules, partners
package them into a separate image that becomes one of the boot
partitions. This entire image is signed, and its signature is
verified by the bootloader at boot time.
> It would then make more sense to me if the protection was determined by
> whether the module is in-tree (the "intree" flag in modinfo) or,
> alternatively, if it is signed by a built-in trusted key. I feel this
> way the feature could be potentially useful for other distributions that
> care about the kABI scope and have ecosystems where vendor modules are
> properly signed with some key. However, I'm not sure if this would still
> work in your case.
Partners can produce both in-tree and out-of-tree modules. We do not
trust either type regarding symbol exposure, as there is no way to know
exactly what sources were used. Furthermore, symbols exported via
EXPORT_SYMBOL_FOR_MODULES can be accessed by any vendor module that
mimics the GKI module name.
Therefore, neither the in-tree flag nor the EXPORT_SYMBOL_FOR_MODULES
mechanism provides a strong enough guarantee for the Android kernel to
identify GKI modules.
Only module signatures are sufficient to allow a module to access the
full set of exported symbols. Unsigned vendor modules may only access
the symbol subset declared ahead of time by partners.
In case such symbol protection is not useful for the Linux community, I
am happy to keep this as an Android-specific feature. However, I would
urge you to at least accept the kflagstab, as it allows us (and
potentially other Linux distributions) to easily introduce additional
flags for symbols. It is also a simplification/clean-up of the module
loader code.
--
Thanks,
Siddharth Nayyar
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [RFC PATCH 00/10] scalable symbol flags with __kflagstab
2025-09-15 15:53 ` Sid Nayyar
@ 2025-09-22 11:41 ` Petr Pavlu
2025-09-26 0:11 ` Sid Nayyar
0 siblings, 1 reply; 22+ messages in thread
From: Petr Pavlu @ 2025-09-22 11:41 UTC (permalink / raw)
To: Sid Nayyar
Cc: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen,
Nicolas Schier, Arnd Bergmann, linux-kbuild, linux-arch,
linux-modules, linux-kernel, Giuliano Procida,
Matthias Männich
On 9/15/25 5:53 PM, Sid Nayyar wrote:
> On Mon, Sep 8, 2025 at 11:09 AM Petr Pavlu <petr.pavlu@suse.com> wrote:
>> This sounds reasonable to me. Do you have any numbers on hand that would
>> show the impact of extending __ksymtab?
>
> I did performance analysis for module loading. The kflagstab
> optimizes symbol search, which accounts for less than 2% of the
> average module load time. Therefore, this change does not translate
> into any meaningful gains (or losses) in module loading performance.
>
> On the binary size side, the on-disk size for vmlinux is somewhat
> inflated due to extra entries in .symtab and .strtab. Since these
> sections are not part of the final Image, the only increase in the
> in-memory size of the kernel is for the kflagstab itself. This new
> table occupies 1 byte for each symbol in the ksymtab.
This is useful information. However, I was specifically interested in
the impact of having the new flags field present as part of __ksymtab
(kernel_symbol), compared to keeping it in a separate section. Sorry for
not being clear.
I ran a small test to get a better understanding of the different sizes.
I used v6.17-rc6 together with the openSUSE x86_64 config [1], which is
fairly large. The resulting vmlinux.bin (no debuginfo) had an on-disk
size of 58 MiB, and included 5937 + 6589 (GPL-only) exported symbols.
The following table summarizes my measurements and calculations
regarding the sizes of all sections related to exported symbols:
| HAVE_ARCH_PREL32_RELOCATIONS | !HAVE_ARCH_PREL32_RELOCATIONS
Section | Base [B] | Ext. [B] | Sep. [B] | Base [B] | Ext. [B] | Sep. [B]
----------------------------------------------------------------------------------------
__ksymtab | 71244 | 200416 | 150312 | 142488 | 400832 | 300624
__ksymtab_gpl | 79068 | NA | NA | 158136 | NA | NA
__kcrctab | 23748 | 50104 | 50104 | 23748 | 50104 | 50104
__kcrctab_gpl | 26356 | NA | NA | 26356 | NA | NA
__ksymtab_strings | 253628 | 253628 | 253628 | 253628 | 253628 | 253628
__kflagstab | NA | NA | 12526 | NA | NA | 12526
----------------------------------------------------------------------------------------
Total | 454044 | 504148 | 466570 | 604356 | 704564 | 616882
Increase to base [%] | NA | 11.0 | 2.8 | NA | 16.6 | 2.1
The column "HAVE_ARCH_PREL32_RELOCATIONS -> Base" contains the numbers
that I measured. The rest of the values are calculated. The "Ext."
column represents the variant of extending __ksymtab, and the "Sep."
column represents the variant of having a separate __kflagstab. With
HAVE_ARCH_PREL32_RELOCATIONS, each kernel_symbol is 12 B in size and is
extended to 16 B. With !HAVE_ARCH_PREL32_RELOCATIONS, it is 24 B,
extended to 32 B. Note that this does not include the metadata needed to
relocate __ksymtab*, which is freed after the initial processing.
The base export data in this case totals 0.43 MiB. About 50% is used for
storing the names of exported symbols.
Adding __kflagstab as a separate section has a negligible impact, as
expected. When extending __ksymtab (kernel_symbol) instead, the worst
case with !HAVE_ARCH_PREL32_RELOCATIONS increases the export data size
by 16.6%.
Based on the above, I think introducing __kflagstab makes senses, as the
added complexity is minimal, although I feel we could probably also get
away with extending kernel_symbol.
>
>>> The Android Common Kernel source is compiled into what we call
>>> GKI (Generic Kernel Image), which consists of a kernel and a
>>> number of modules. We maintain a stable interface (based on CRCs and
>>> types) between the GKI components and vendor-specific modules
>>> (compiled by device manufacturers, e.g., for hardware-specific
>>> drivers) for the lifetime of a given GKI version.
>>>
>>> This interface is intentionally restricted to the minimal set of
>>> symbols required by the union of all vendor modules; our partners
>>> declare their requirements in symbol lists. Any additions to these
>>> lists are reviewed to ensure kernel internals are not overly exposed.
>>> For example, we restrict drivers from having the ability to open and
>>> read arbitrary files. This ABI boundary also allows us to evolve
>>> internal kernel types that are not exposed to vendor modules, for
>>> example, when a security fix requires a type to change.
>>>
>>> The mechanism we use for this is CONFIG_TRIM_UNUSED_KSYMS and
>>> CONFIG_UNUSED_KSYMS_WHITELIST. This results in a ksymtab
>>> containing two kinds of exported symbols: those explicitly required
>>> by vendors ("vendor-listed") and those only required by GKI modules
>>> ("GKI use only").
>>>
>>> On top of this, we have implemented symbol import protection
>>> (covered in patches 9/10 and 10/10). This feature prevents vendor
>>> modules from using symbols that are not on the vendor-listed
>>> whitelist. It is built on top of CONFIG_MODULE_SIG. GKI modules are
>>> signed with a specific key, while vendor modules are unsigned and thus
>>> treated as untrusted. This distinction allows signed GKI modules to
>>> use any symbol in the ksymtab, while unsigned vendor modules can only
>>> access the declared subset. This provides a significant layer of
>>> defense and security against potentially exploitable vendor module
>>> code.
>>
>> If I understand correctly, this is similar to the recently introduced
>> EXPORT_SYMBOL_FOR_MODULES() macro, but with a coarser boundary.
>>
>> I think that if the goal is to control the kABI scope and limit the use
>> of certain symbols only to GKI modules, then having the protection
>> depend on whether the module is signed is somewhat odd. It doesn't give
>> me much confidence if vendor modules are unsigned in the Android
>> ecosystem. I would expect that you want to improve this in the long
>> term.
>
> GKI modules are the only modules built in the same Kbuild as the
> kernel image, which Google builds and provides to partners. In
> contrast, vendor modules are built and packaged entirely by partners.
>
> Google signs GKI modules with ephemeral keys. Since partners do
> not have these keys, vendor modules are treated as unsigned by
> the kernel.
>
> To ensure the authenticity of these unsigned modules, partners
> package them into a separate image that becomes one of the boot
> partitions. This entire image is signed, and its signature is
> verified by the bootloader at boot time.
>
>> It would then make more sense to me if the protection was determined by
>> whether the module is in-tree (the "intree" flag in modinfo) or,
>> alternatively, if it is signed by a built-in trusted key. I feel this
>> way the feature could be potentially useful for other distributions that
>> care about the kABI scope and have ecosystems where vendor modules are
>> properly signed with some key. However, I'm not sure if this would still
>> work in your case.
>
> Partners can produce both in-tree and out-of-tree modules. We do not
> trust either type regarding symbol exposure, as there is no way to know
> exactly what sources were used. Furthermore, symbols exported via
> EXPORT_SYMBOL_FOR_MODULES can be accessed by any vendor module that
> mimics the GKI module name.
>
> Therefore, neither the in-tree flag nor the EXPORT_SYMBOL_FOR_MODULES
> mechanism provides a strong enough guarantee for the Android kernel to
> identify GKI modules.
>
> Only module signatures are sufficient to allow a module to access the
> full set of exported symbols. Unsigned vendor modules may only access
> the symbol subset declared ahead of time by partners.
This seems to answer why the in-tree flag is not sufficient for you.
However, I also suggested an alternative that the symbol protection
could be determined by whether the module is signed by a key from the
.builtin_trusted_keys keyring, as opposed to being signed by another key
reachable from the .secondary_trusted_keys keyring or being completely
unsigned.
Distributions can require that external modules be signed and allow
additional keys to be added as Machine Owner Keys, which can be made
reachable from .secondary_trusted_keys. Nonetheless, such distributions
might be still interested in limiting the number of symbols that such
external modules can use.
I think this option is worth considering, as it could potentially make
this symbol protection useful for other distributions as well.
>
> In case such symbol protection is not useful for the Linux community, I
> am happy to keep this as an Android-specific feature. However, I would
> urge you to at least accept the kflagstab, as it allows us (and
> potentially other Linux distributions) to easily introduce additional
> flags for symbols. It is also a simplification/clean-up of the module
> loader code.
I'm personally ok with adding the kflagstab support. I think it
introduces minimal complexity and, as you point out, simplifies certain
aspects. Additionally, if we add it, I believe that adding the proposed
symbol protection is simple enough to be included as well, at least from
my perspective.
[1] https://github.com/openSUSE/kernel-source/blob/307f149d9100a0e229eb94cbb997ae61187995c3/config/x86_64/default
--
Thanks,
Petr
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [RFC PATCH 00/10] scalable symbol flags with __kflagstab
2025-09-22 11:41 ` Petr Pavlu
@ 2025-09-26 0:11 ` Sid Nayyar
0 siblings, 0 replies; 22+ messages in thread
From: Sid Nayyar @ 2025-09-26 0:11 UTC (permalink / raw)
To: Petr Pavlu
Cc: Nathan Chancellor, Luis Chamberlain, Sami Tolvanen,
Nicolas Schier, Arnd Bergmann, linux-kbuild, linux-arch,
linux-modules, linux-kernel, Giuliano Procida,
Matthias Männich
On Mon, Sep 22, 2025 at 12:41 PM Petr Pavlu <petr.pavlu@suse.com> wrote:
> This is useful information. However, I was specifically interested in
> the impact of having the new flags field present as part of __ksymtab
> (kernel_symbol), compared to keeping it in a separate section. Sorry for
> not being clear.
>
> I ran a small test to get a better understanding of the different sizes.
> I used v6.17-rc6 together with the openSUSE x86_64 config [1], which is
> fairly large. The resulting vmlinux.bin (no debuginfo) had an on-disk
> size of 58 MiB, and included 5937 + 6589 (GPL-only) exported symbols.
>
> The following table summarizes my measurements and calculations
> regarding the sizes of all sections related to exported symbols:
>
> | HAVE_ARCH_PREL32_RELOCATIONS | !HAVE_ARCH_PREL32_RELOCATIONS
> Section | Base [B] | Ext. [B] | Sep. [B] | Base [B] | Ext. [B] | Sep. [B]
> ----------------------------------------------------------------------------------------
> __ksymtab | 71244 | 200416 | 150312 | 142488 | 400832 | 300624
> __ksymtab_gpl | 79068 | NA | NA | 158136 | NA | NA
> __kcrctab | 23748 | 50104 | 50104 | 23748 | 50104 | 50104
> __kcrctab_gpl | 26356 | NA | NA | 26356 | NA | NA
> __ksymtab_strings | 253628 | 253628 | 253628 | 253628 | 253628 | 253628
> __kflagstab | NA | NA | 12526 | NA | NA | 12526
> ----------------------------------------------------------------------------------------
> Total | 454044 | 504148 | 466570 | 604356 | 704564 | 616882
> Increase to base [%] | NA | 11.0 | 2.8 | NA | 16.6 | 2.1
>
> The column "HAVE_ARCH_PREL32_RELOCATIONS -> Base" contains the numbers
> that I measured. The rest of the values are calculated. The "Ext."
> column represents the variant of extending __ksymtab, and the "Sep."
> column represents the variant of having a separate __kflagstab. With
> HAVE_ARCH_PREL32_RELOCATIONS, each kernel_symbol is 12 B in size and is
> extended to 16 B. With !HAVE_ARCH_PREL32_RELOCATIONS, it is 24 B,
> extended to 32 B. Note that this does not include the metadata needed to
> relocate __ksymtab*, which is freed after the initial processing.
>
> The base export data in this case totals 0.43 MiB. About 50% is used for
> storing the names of exported symbols.
>
> Adding __kflagstab as a separate section has a negligible impact, as
> expected. When extending __ksymtab (kernel_symbol) instead, the worst
> case with !HAVE_ARCH_PREL32_RELOCATIONS increases the export data size
> by 16.6%.
>
> Based on the above, I think introducing __kflagstab makes senses, as the
> added complexity is minimal, although I feel we could probably also get
> away with extending kernel_symbol.
This investigation is very informative, thank you for sharing your
findings. I am in agreement with your conclusions.
> This seems to answer why the in-tree flag is not sufficient for you.
> However, I also suggested an alternative that the symbol protection
> could be determined by whether the module is signed by a key from the
> .builtin_trusted_keys keyring, as opposed to being signed by another key
> reachable from the .secondary_trusted_keys keyring or being completely
> unsigned.
>
> Distributions can require that external modules be signed and allow
> additional keys to be added as Machine Owner Keys, which can be made
> reachable from .secondary_trusted_keys. Nonetheless, such distributions
> might be still interested in limiting the number of symbols that such
> external modules can use.
>
> I think this option is worth considering, as it could potentially make
> this symbol protection useful for other distributions as well.
This sounds like a great solution to enhance trust and security,
apologies for missing this in the previous email. I will explore this
approach, but I would like to do it in a separate series.
> I'm personally ok with adding the kflagstab support. I think it
> introduces minimal complexity and, as you point out, simplifies certain
> aspects. Additionally, if we add it, I believe that adding the proposed
> symbol protection is simple enough to be included as well, at least from
> my perspective.
Since we are in agreement, I would like to seek code review for this
series. The code is ready for review from my side, but if you prefer I
can send out a non-RFC patch series for code review.
--
Thanks,
Siddharth Nayyar
^ permalink raw reply [flat|nested] 22+ messages in thread