Skip to content

Commit 8651ec0

Browse files
mettiJessica Yu
authored andcommitted
module: add support for symbol namespaces.
The EXPORT_SYMBOL_NS() and EXPORT_SYMBOL_NS_GPL() macros can be used to export a symbol to a specific namespace. There are no _GPL_FUTURE and _UNUSED variants because these are currently unused, and I'm not sure they are necessary. I didn't add EXPORT_SYMBOL_NS() for ASM exports; this patch sets the namespace of ASM exports to NULL by default. In case of relative references, it will be relocatable to NULL. If there's a need, this should be pretty easy to add. A module that wants to use a symbol exported to a namespace must add a MODULE_IMPORT_NS() statement to their module code; otherwise, modpost will complain when building the module, and the kernel module loader will emit an error and fail when loading the module. MODULE_IMPORT_NS() adds a modinfo tag 'import_ns' to the module. That tag can be observed by the modinfo command, modpost and kernel/module.c at the time of loading the module. The ELF symbols are renamed to include the namespace with an asm label; for example, symbol 'usb_stor_suspend' in namespace USB_STORAGE becomes 'usb_stor_suspend.USB_STORAGE'. This allows modpost to do namespace checking, without having to go through all the effort of parsing ELF and relocation records just to get to the struct kernel_symbols. On x86_64 I saw no difference in binary size (compression), but at runtime this will require a word of memory per export to hold the namespace. An alternative could be to store namespaced symbols in their own section and use a separate 'struct namespaced_kernel_symbol' for that section, at the cost of making the module loader more complex. Co-developed-by: Martijn Coenen <[email protected]> Signed-off-by: Martijn Coenen <[email protected]> Reviewed-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Matthias Maennich <[email protected]> Signed-off-by: Jessica Yu <[email protected]>
1 parent ed13fc3 commit 8651ec0

File tree

4 files changed

+123
-19
lines changed

4 files changed

+123
-19
lines changed

include/asm-generic/export.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717

1818
.macro __put, val, name
1919
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
20-
.long \val - ., \name - .
20+
.long \val - ., \name - ., 0 - .
2121
#elif defined(CONFIG_64BIT)
22-
.quad \val, \name
22+
.quad \val, \name, 0
2323
#else
24-
.long \val, \name
24+
.long \val, \name, 0
2525
#endif
2626
.endm
2727

include/linux/export.h

Lines changed: 75 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ extern struct module __this_module;
2020

2121
#ifdef CONFIG_MODULES
2222

23+
#define NS_SEPARATOR "."
24+
2325
#if defined(__KERNEL__) && !defined(__GENKSYMS__)
2426
#ifdef CONFIG_MODVERSIONS
2527
/* Mark the CRC weak since genksyms apparently decides not to
@@ -29,13 +31,13 @@ extern struct module __this_module;
2931
asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
3032
" .weak __crc_" #sym " \n" \
3133
" .long __crc_" #sym " - . \n" \
32-
" .previous \n");
34+
" .previous \n")
3335
#else
3436
#define __CRC_SYMBOL(sym, sec) \
3537
asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
3638
" .weak __crc_" #sym " \n" \
3739
" .long __crc_" #sym " \n" \
38-
" .previous \n");
40+
" .previous \n")
3941
#endif
4042
#else
4143
#define __CRC_SYMBOL(sym, sec)
@@ -49,39 +51,70 @@ extern struct module __this_module;
4951
* absolute relocations that require runtime processing on relocatable
5052
* kernels.
5153
*/
54+
#define __KSYMTAB_ENTRY_NS(sym, sec, ns) \
55+
__ADDRESSABLE(sym) \
56+
asm(" .section \"___ksymtab" sec "+" #sym "\", \"a\" \n" \
57+
" .balign 4 \n" \
58+
"__ksymtab_" #sym NS_SEPARATOR #ns ": \n" \
59+
" .long " #sym "- . \n" \
60+
" .long __kstrtab_" #sym "- . \n" \
61+
" .long __kstrtab_ns_" #sym "- . \n" \
62+
" .previous \n")
63+
5264
#define __KSYMTAB_ENTRY(sym, sec) \
5365
__ADDRESSABLE(sym) \
5466
asm(" .section \"___ksymtab" sec "+" #sym "\", \"a\" \n" \
5567
" .balign 4 \n" \
5668
"__ksymtab_" #sym ": \n" \
5769
" .long " #sym "- . \n" \
5870
" .long __kstrtab_" #sym "- . \n" \
71+
" .long 0 - . \n" \
5972
" .previous \n")
6073

6174
struct kernel_symbol {
6275
int value_offset;
6376
int name_offset;
77+
int namespace_offset;
6478
};
6579
#else
80+
#define __KSYMTAB_ENTRY_NS(sym, sec, ns) \
81+
static const struct kernel_symbol __ksymtab_##sym##__##ns \
82+
asm("__ksymtab_" #sym NS_SEPARATOR #ns) \
83+
__attribute__((section("___ksymtab" sec "+" #sym), used)) \
84+
__aligned(sizeof(void *)) \
85+
= { (unsigned long)&sym, __kstrtab_##sym, __kstrtab_ns_##sym }
86+
6687
#define __KSYMTAB_ENTRY(sym, sec) \
6788
static const struct kernel_symbol __ksymtab_##sym \
89+
asm("__ksymtab_" #sym) \
6890
__attribute__((section("___ksymtab" sec "+" #sym), used)) \
6991
__aligned(sizeof(void *)) \
70-
= { (unsigned long)&sym, __kstrtab_##sym }
92+
= { (unsigned long)&sym, __kstrtab_##sym, NULL }
7193

7294
struct kernel_symbol {
7395
unsigned long value;
7496
const char *name;
97+
const char *namespace;
7598
};
7699
#endif
77100

78-
/* For every exported symbol, place a struct in the __ksymtab section */
79-
#define ___EXPORT_SYMBOL(sym, sec) \
101+
#define ___export_symbol_common(sym, sec) \
80102
extern typeof(sym) sym; \
81-
__CRC_SYMBOL(sym, sec) \
103+
__CRC_SYMBOL(sym, sec); \
82104
static const char __kstrtab_##sym[] \
83105
__attribute__((section("__ksymtab_strings"), used, aligned(1))) \
84-
= #sym; \
106+
= #sym \
107+
108+
/* For every exported symbol, place a struct in the __ksymtab section */
109+
#define ___EXPORT_SYMBOL_NS(sym, sec, ns) \
110+
___export_symbol_common(sym, sec); \
111+
static const char __kstrtab_ns_##sym[] \
112+
__attribute__((section("__ksymtab_strings"), used, aligned(1))) \
113+
= #ns; \
114+
__KSYMTAB_ENTRY_NS(sym, sec, ns)
115+
116+
#define ___EXPORT_SYMBOL(sym, sec) \
117+
___export_symbol_common(sym, sec); \
85118
__KSYMTAB_ENTRY(sym, sec)
86119

87120
#if defined(__DISABLE_EXPORTS)
@@ -91,6 +124,7 @@ struct kernel_symbol {
91124
* be reused in other execution contexts such as the UEFI stub or the
92125
* decompressor.
93126
*/
127+
#define __EXPORT_SYMBOL_NS(sym, sec, ns)
94128
#define __EXPORT_SYMBOL(sym, sec)
95129

96130
#elif defined(CONFIG_TRIM_UNUSED_KSYMS)
@@ -117,18 +151,26 @@ struct kernel_symbol {
117151
#define __cond_export_sym_1(sym, sec) ___EXPORT_SYMBOL(sym, sec)
118152
#define __cond_export_sym_0(sym, sec) /* nothing */
119153

154+
#define __EXPORT_SYMBOL_NS(sym, sec, ns) \
155+
__ksym_marker(sym); \
156+
__cond_export_ns_sym(sym, sec, ns, __is_defined(__KSYM_##sym))
157+
#define __cond_export_ns_sym(sym, sec, ns, conf) \
158+
___cond_export_ns_sym(sym, sec, ns, conf)
159+
#define ___cond_export_ns_sym(sym, sec, ns, enabled) \
160+
__cond_export_ns_sym_##enabled(sym, sec, ns)
161+
#define __cond_export_ns_sym_1(sym, sec, ns) ___EXPORT_SYMBOL_NS(sym, sec, ns)
162+
#define __cond_export_ns_sym_0(sym, sec, ns) /* nothing */
163+
120164
#else
165+
#define __EXPORT_SYMBOL_NS ___EXPORT_SYMBOL_NS
121166
#define __EXPORT_SYMBOL ___EXPORT_SYMBOL
122167
#endif
123168

124-
#define EXPORT_SYMBOL(sym) \
125-
__EXPORT_SYMBOL(sym, "")
126-
127-
#define EXPORT_SYMBOL_GPL(sym) \
128-
__EXPORT_SYMBOL(sym, "_gpl")
129-
130-
#define EXPORT_SYMBOL_GPL_FUTURE(sym) \
131-
__EXPORT_SYMBOL(sym, "_gpl_future")
169+
#define EXPORT_SYMBOL(sym) __EXPORT_SYMBOL(sym, "")
170+
#define EXPORT_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_gpl")
171+
#define EXPORT_SYMBOL_GPL_FUTURE(sym) __EXPORT_SYMBOL(sym, "_gpl_future")
172+
#define EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL_NS(sym, "", ns)
173+
#define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL_NS(sym, "_gpl", ns)
132174

133175
#ifdef CONFIG_UNUSED_SYMBOLS
134176
#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
@@ -138,11 +180,28 @@ struct kernel_symbol {
138180
#define EXPORT_UNUSED_SYMBOL_GPL(sym)
139181
#endif
140182

141-
#endif /* __GENKSYMS__ */
183+
#endif /* __KERNEL__ && !__GENKSYMS__ */
184+
185+
#if defined(__GENKSYMS__)
186+
/*
187+
* When we're running genksyms, ignore the namespace and make the _NS
188+
* variants look like the normal ones. There are two reasons for this:
189+
* 1) In the normal definition of EXPORT_SYMBOL_NS, the 'ns' macro
190+
* argument is itself not expanded because it's always tokenized or
191+
* concatenated; but when running genksyms, a blank definition of the
192+
* macro does allow the argument to be expanded; if a namespace
193+
* happens to collide with a #define, this can cause issues.
194+
* 2) There's no need to modify genksyms to deal with the _NS variants
195+
*/
196+
#define EXPORT_SYMBOL_NS(sym, ns) EXPORT_SYMBOL(sym)
197+
#define EXPORT_SYMBOL_NS_GPL(sym, ns) EXPORT_SYMBOL_GPL(sym)
198+
#endif
142199

143200
#else /* !CONFIG_MODULES... */
144201

145202
#define EXPORT_SYMBOL(sym)
203+
#define EXPORT_SYMBOL_NS(sym, ns)
204+
#define EXPORT_SYMBOL_NS_GPL(sym, ns)
146205
#define EXPORT_SYMBOL_GPL(sym)
147206
#define EXPORT_SYMBOL_GPL_FUTURE(sym)
148207
#define EXPORT_UNUSED_SYMBOL(sym)

include/linux/module.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ struct notifier_block;
280280

281281
#ifdef CONFIG_MODULES
282282

283+
#define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns)
284+
283285
extern int modules_disabled; /* for sysctl */
284286
/* Get/put a kernel symbol (calls must be symmetric) */
285287
void *__symbol_get(const char *symbol);

kernel/module.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,15 @@ static const char *kernel_symbol_name(const struct kernel_symbol *sym)
544544
#endif
545545
}
546546

547+
static const char *kernel_symbol_namespace(const struct kernel_symbol *sym)
548+
{
549+
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
550+
return offset_to_ptr(&sym->namespace_offset);
551+
#else
552+
return sym->namespace;
553+
#endif
554+
}
555+
547556
static int cmp_name(const void *va, const void *vb)
548557
{
549558
const char *a;
@@ -1379,6 +1388,34 @@ static inline int same_magic(const char *amagic, const char *bmagic,
13791388
}
13801389
#endif /* CONFIG_MODVERSIONS */
13811390

1391+
static char *get_modinfo(const struct load_info *info, const char *tag);
1392+
static char *get_next_modinfo(const struct load_info *info, const char *tag,
1393+
char *prev);
1394+
1395+
static int verify_namespace_is_imported(const struct load_info *info,
1396+
const struct kernel_symbol *sym,
1397+
struct module *mod)
1398+
{
1399+
const char *namespace;
1400+
char *imported_namespace;
1401+
1402+
namespace = kernel_symbol_namespace(sym);
1403+
if (namespace) {
1404+
imported_namespace = get_modinfo(info, "import_ns");
1405+
while (imported_namespace) {
1406+
if (strcmp(namespace, imported_namespace) == 0)
1407+
return 0;
1408+
imported_namespace = get_next_modinfo(
1409+
info, "import_ns", imported_namespace);
1410+
}
1411+
pr_err("%s: module uses symbol (%s) from namespace %s, but does not import it.\n",
1412+
mod->name, kernel_symbol_name(sym), namespace);
1413+
return -EINVAL;
1414+
}
1415+
return 0;
1416+
}
1417+
1418+
13821419
/* Resolve a symbol for this module. I.e. if we find one, record usage. */
13831420
static const struct kernel_symbol *resolve_symbol(struct module *mod,
13841421
const struct load_info *info,
@@ -1407,6 +1444,12 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
14071444
goto getname;
14081445
}
14091446

1447+
err = verify_namespace_is_imported(info, sym, mod);
1448+
if (err) {
1449+
sym = ERR_PTR(err);
1450+
goto getname;
1451+
}
1452+
14101453
err = ref_module(mod, owner);
14111454
if (err) {
14121455
sym = ERR_PTR(err);

0 commit comments

Comments
 (0)