diff options
author | Matthias Maennich <maennich@google.com> | 2019-09-06 06:32:27 -0400 |
---|---|---|
committer | Jessica Yu <jeyu@kernel.org> | 2019-09-10 04:30:17 -0400 |
commit | 8651ec01daedad26290f76beeb4736f9d2da4b87 (patch) | |
tree | addd8a0c1a51b5000c96218a1b349fde30ff4f29 | |
parent | ed13fc33f763035a7c290f11c7111877c3a5daab (diff) |
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 <maco@android.com>
Signed-off-by: Martijn Coenen <maco@android.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Matthias Maennich <maennich@google.com>
Signed-off-by: Jessica Yu <jeyu@kernel.org>
-rw-r--r-- | include/asm-generic/export.h | 6 | ||||
-rw-r--r-- | include/linux/export.h | 91 | ||||
-rw-r--r-- | include/linux/module.h | 2 | ||||
-rw-r--r-- | kernel/module.c | 43 |
4 files changed, 123 insertions, 19 deletions
diff --git a/include/asm-generic/export.h b/include/asm-generic/export.h index 63f54907317b..e2b5d0f569d3 100644 --- a/include/asm-generic/export.h +++ b/include/asm-generic/export.h | |||
@@ -17,11 +17,11 @@ | |||
17 | 17 | ||
18 | .macro __put, val, name | 18 | .macro __put, val, name |
19 | #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS | 19 | #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS |
20 | .long \val - ., \name - . | 20 | .long \val - ., \name - ., 0 - . |
21 | #elif defined(CONFIG_64BIT) | 21 | #elif defined(CONFIG_64BIT) |
22 | .quad \val, \name | 22 | .quad \val, \name, 0 |
23 | #else | 23 | #else |
24 | .long \val, \name | 24 | .long \val, \name, 0 |
25 | #endif | 25 | #endif |
26 | .endm | 26 | .endm |
27 | 27 | ||
diff --git a/include/linux/export.h b/include/linux/export.h index 28a4d2150689..d59461e71478 100644 --- a/include/linux/export.h +++ b/include/linux/export.h | |||
@@ -20,6 +20,8 @@ extern struct module __this_module; | |||
20 | 20 | ||
21 | #ifdef CONFIG_MODULES | 21 | #ifdef CONFIG_MODULES |
22 | 22 | ||
23 | #define NS_SEPARATOR "." | ||
24 | |||
23 | #if defined(__KERNEL__) && !defined(__GENKSYMS__) | 25 | #if defined(__KERNEL__) && !defined(__GENKSYMS__) |
24 | #ifdef CONFIG_MODVERSIONS | 26 | #ifdef CONFIG_MODVERSIONS |
25 | /* Mark the CRC weak since genksyms apparently decides not to | 27 | /* Mark the CRC weak since genksyms apparently decides not to |
@@ -29,13 +31,13 @@ extern struct module __this_module; | |||
29 | asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \ | 31 | asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \ |
30 | " .weak __crc_" #sym " \n" \ | 32 | " .weak __crc_" #sym " \n" \ |
31 | " .long __crc_" #sym " - . \n" \ | 33 | " .long __crc_" #sym " - . \n" \ |
32 | " .previous \n"); | 34 | " .previous \n") |
33 | #else | 35 | #else |
34 | #define __CRC_SYMBOL(sym, sec) \ | 36 | #define __CRC_SYMBOL(sym, sec) \ |
35 | asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \ | 37 | asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \ |
36 | " .weak __crc_" #sym " \n" \ | 38 | " .weak __crc_" #sym " \n" \ |
37 | " .long __crc_" #sym " \n" \ | 39 | " .long __crc_" #sym " \n" \ |
38 | " .previous \n"); | 40 | " .previous \n") |
39 | #endif | 41 | #endif |
40 | #else | 42 | #else |
41 | #define __CRC_SYMBOL(sym, sec) | 43 | #define __CRC_SYMBOL(sym, sec) |
@@ -49,6 +51,16 @@ extern struct module __this_module; | |||
49 | * absolute relocations that require runtime processing on relocatable | 51 | * absolute relocations that require runtime processing on relocatable |
50 | * kernels. | 52 | * kernels. |
51 | */ | 53 | */ |
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 | |||
52 | #define __KSYMTAB_ENTRY(sym, sec) \ | 64 | #define __KSYMTAB_ENTRY(sym, sec) \ |
53 | __ADDRESSABLE(sym) \ | 65 | __ADDRESSABLE(sym) \ |
54 | asm(" .section \"___ksymtab" sec "+" #sym "\", \"a\" \n" \ | 66 | asm(" .section \"___ksymtab" sec "+" #sym "\", \"a\" \n" \ |
@@ -56,32 +68,53 @@ extern struct module __this_module; | |||
56 | "__ksymtab_" #sym ": \n" \ | 68 | "__ksymtab_" #sym ": \n" \ |
57 | " .long " #sym "- . \n" \ | 69 | " .long " #sym "- . \n" \ |
58 | " .long __kstrtab_" #sym "- . \n" \ | 70 | " .long __kstrtab_" #sym "- . \n" \ |
71 | " .long 0 - . \n" \ | ||
59 | " .previous \n") | 72 | " .previous \n") |
60 | 73 | ||
61 | struct kernel_symbol { | 74 | struct kernel_symbol { |
62 | int value_offset; | 75 | int value_offset; |
63 | int name_offset; | 76 | int name_offset; |
77 | int namespace_offset; | ||
64 | }; | 78 | }; |
65 | #else | 79 | #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 | |||
66 | #define __KSYMTAB_ENTRY(sym, sec) \ | 87 | #define __KSYMTAB_ENTRY(sym, sec) \ |
67 | static const struct kernel_symbol __ksymtab_##sym \ | 88 | static const struct kernel_symbol __ksymtab_##sym \ |
89 | asm("__ksymtab_" #sym) \ | ||
68 | __attribute__((section("___ksymtab" sec "+" #sym), used)) \ | 90 | __attribute__((section("___ksymtab" sec "+" #sym), used)) \ |
69 | __aligned(sizeof(void *)) \ | 91 | __aligned(sizeof(void *)) \ |
70 | = { (unsigned long)&sym, __kstrtab_##sym } | 92 | = { (unsigned long)&sym, __kstrtab_##sym, NULL } |
71 | 93 | ||
72 | struct kernel_symbol { | 94 | struct kernel_symbol { |
73 | unsigned long value; | 95 | unsigned long value; |
74 | const char *name; | 96 | const char *name; |
97 | const char *namespace; | ||
75 | }; | 98 | }; |
76 | #endif | 99 | #endif |
77 | 100 | ||
78 | /* For every exported symbol, place a struct in the __ksymtab section */ | 101 | #define ___export_symbol_common(sym, sec) \ |
79 | #define ___EXPORT_SYMBOL(sym, sec) \ | ||
80 | extern typeof(sym) sym; \ | 102 | extern typeof(sym) sym; \ |
81 | __CRC_SYMBOL(sym, sec) \ | 103 | __CRC_SYMBOL(sym, sec); \ |
82 | static const char __kstrtab_##sym[] \ | 104 | static const char __kstrtab_##sym[] \ |
83 | __attribute__((section("__ksymtab_strings"), used, aligned(1))) \ | 105 | __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); \ | ||
85 | __KSYMTAB_ENTRY(sym, sec) | 118 | __KSYMTAB_ENTRY(sym, sec) |
86 | 119 | ||
87 | #if defined(__DISABLE_EXPORTS) | 120 | #if defined(__DISABLE_EXPORTS) |
@@ -91,6 +124,7 @@ struct kernel_symbol { | |||
91 | * be reused in other execution contexts such as the UEFI stub or the | 124 | * be reused in other execution contexts such as the UEFI stub or the |
92 | * decompressor. | 125 | * decompressor. |
93 | */ | 126 | */ |
127 | #define __EXPORT_SYMBOL_NS(sym, sec, ns) | ||
94 | #define __EXPORT_SYMBOL(sym, sec) | 128 | #define __EXPORT_SYMBOL(sym, sec) |
95 | 129 | ||
96 | #elif defined(CONFIG_TRIM_UNUSED_KSYMS) | 130 | #elif defined(CONFIG_TRIM_UNUSED_KSYMS) |
@@ -117,18 +151,26 @@ struct kernel_symbol { | |||
117 | #define __cond_export_sym_1(sym, sec) ___EXPORT_SYMBOL(sym, sec) | 151 | #define __cond_export_sym_1(sym, sec) ___EXPORT_SYMBOL(sym, sec) |
118 | #define __cond_export_sym_0(sym, sec) /* nothing */ | 152 | #define __cond_export_sym_0(sym, sec) /* nothing */ |
119 | 153 | ||
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 | |||
120 | #else | 164 | #else |
165 | #define __EXPORT_SYMBOL_NS ___EXPORT_SYMBOL_NS | ||
121 | #define __EXPORT_SYMBOL ___EXPORT_SYMBOL | 166 | #define __EXPORT_SYMBOL ___EXPORT_SYMBOL |
122 | #endif | 167 | #endif |
123 | 168 | ||
124 | #define EXPORT_SYMBOL(sym) \ | 169 | #define EXPORT_SYMBOL(sym) __EXPORT_SYMBOL(sym, "") |
125 | __EXPORT_SYMBOL(sym, "") | 170 | #define EXPORT_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_gpl") |
126 | 171 | #define EXPORT_SYMBOL_GPL_FUTURE(sym) __EXPORT_SYMBOL(sym, "_gpl_future") | |
127 | #define EXPORT_SYMBOL_GPL(sym) \ | 172 | #define EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL_NS(sym, "", ns) |
128 | __EXPORT_SYMBOL(sym, "_gpl") | 173 | #define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL_NS(sym, "_gpl", ns) |
129 | |||
130 | #define EXPORT_SYMBOL_GPL_FUTURE(sym) \ | ||
131 | __EXPORT_SYMBOL(sym, "_gpl_future") | ||
132 | 174 | ||
133 | #ifdef CONFIG_UNUSED_SYMBOLS | 175 | #ifdef CONFIG_UNUSED_SYMBOLS |
134 | #define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused") | 176 | #define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused") |
@@ -138,11 +180,28 @@ struct kernel_symbol { | |||
138 | #define EXPORT_UNUSED_SYMBOL_GPL(sym) | 180 | #define EXPORT_UNUSED_SYMBOL_GPL(sym) |
139 | #endif | 181 | #endif |
140 | 182 | ||
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 | ||
142 | 199 | ||
143 | #else /* !CONFIG_MODULES... */ | 200 | #else /* !CONFIG_MODULES... */ |
144 | 201 | ||
145 | #define EXPORT_SYMBOL(sym) | 202 | #define EXPORT_SYMBOL(sym) |
203 | #define EXPORT_SYMBOL_NS(sym, ns) | ||
204 | #define EXPORT_SYMBOL_NS_GPL(sym, ns) | ||
146 | #define EXPORT_SYMBOL_GPL(sym) | 205 | #define EXPORT_SYMBOL_GPL(sym) |
147 | #define EXPORT_SYMBOL_GPL_FUTURE(sym) | 206 | #define EXPORT_SYMBOL_GPL_FUTURE(sym) |
148 | #define EXPORT_UNUSED_SYMBOL(sym) | 207 | #define EXPORT_UNUSED_SYMBOL(sym) |
diff --git a/include/linux/module.h b/include/linux/module.h index 1455812dd325..b3611e749f72 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -280,6 +280,8 @@ struct notifier_block; | |||
280 | 280 | ||
281 | #ifdef CONFIG_MODULES | 281 | #ifdef CONFIG_MODULES |
282 | 282 | ||
283 | #define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns) | ||
284 | |||
283 | extern int modules_disabled; /* for sysctl */ | 285 | extern int modules_disabled; /* for sysctl */ |
284 | /* Get/put a kernel symbol (calls must be symmetric) */ | 286 | /* Get/put a kernel symbol (calls must be symmetric) */ |
285 | void *__symbol_get(const char *symbol); | 287 | void *__symbol_get(const char *symbol); |
diff --git a/kernel/module.c b/kernel/module.c index 3ee507c0a92f..6bb9b938f9c7 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -544,6 +544,15 @@ static const char *kernel_symbol_name(const struct kernel_symbol *sym) | |||
544 | #endif | 544 | #endif |
545 | } | 545 | } |
546 | 546 | ||
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 | |||
547 | static int cmp_name(const void *va, const void *vb) | 556 | static int cmp_name(const void *va, const void *vb) |
548 | { | 557 | { |
549 | const char *a; | 558 | const char *a; |
@@ -1379,6 +1388,34 @@ static inline int same_magic(const char *amagic, const char *bmagic, | |||
1379 | } | 1388 | } |
1380 | #endif /* CONFIG_MODVERSIONS */ | 1389 | #endif /* CONFIG_MODVERSIONS */ |
1381 | 1390 | ||
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 | |||
1382 | /* Resolve a symbol for this module. I.e. if we find one, record usage. */ | 1419 | /* Resolve a symbol for this module. I.e. if we find one, record usage. */ |
1383 | static const struct kernel_symbol *resolve_symbol(struct module *mod, | 1420 | static const struct kernel_symbol *resolve_symbol(struct module *mod, |
1384 | const struct load_info *info, | 1421 | const struct load_info *info, |
@@ -1407,6 +1444,12 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod, | |||
1407 | goto getname; | 1444 | goto getname; |
1408 | } | 1445 | } |
1409 | 1446 | ||
1447 | err = verify_namespace_is_imported(info, sym, mod); | ||
1448 | if (err) { | ||
1449 | sym = ERR_PTR(err); | ||
1450 | goto getname; | ||
1451 | } | ||
1452 | |||
1410 | err = ref_module(mod, owner); | 1453 | err = ref_module(mod, owner); |
1411 | if (err) { | 1454 | if (err) { |
1412 | sym = ERR_PTR(err); | 1455 | sym = ERR_PTR(err); |