summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorMatthias Maennich <maennich@google.com>2019-09-06 13:32:27 +0300
committerJessica Yu <jeyu@kernel.org>2019-09-10 11:30:17 +0300
commit8651ec01daedad26290f76beeb4736f9d2da4b87 (patch)
treeaddd8a0c1a51b5000c96218a1b349fde30ff4f29 /include
parented13fc33f763035a7c290f11c7111877c3a5daab (diff)
downloadlinux-8651ec01daedad26290f76beeb4736f9d2da4b87.tar.xz
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>
Diffstat (limited to 'include')
-rw-r--r--include/asm-generic/export.h6
-rw-r--r--include/linux/export.h91
-rw-r--r--include/linux/module.h2
3 files changed, 80 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 @@
.macro __put, val, name
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
- .long \val - ., \name - .
+ .long \val - ., \name - ., 0 - .
#elif defined(CONFIG_64BIT)
- .quad \val, \name
+ .quad \val, \name, 0
#else
- .long \val, \name
+ .long \val, \name, 0
#endif
.endm
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;
#ifdef CONFIG_MODULES
+#define NS_SEPARATOR "."
+
#if defined(__KERNEL__) && !defined(__GENKSYMS__)
#ifdef CONFIG_MODVERSIONS
/* Mark the CRC weak since genksyms apparently decides not to
@@ -29,13 +31,13 @@ extern struct module __this_module;
asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
" .weak __crc_" #sym " \n" \
" .long __crc_" #sym " - . \n" \
- " .previous \n");
+ " .previous \n")
#else
#define __CRC_SYMBOL(sym, sec) \
asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
" .weak __crc_" #sym " \n" \
" .long __crc_" #sym " \n" \
- " .previous \n");
+ " .previous \n")
#endif
#else
#define __CRC_SYMBOL(sym, sec)
@@ -49,6 +51,16 @@ extern struct module __this_module;
* absolute relocations that require runtime processing on relocatable
* kernels.
*/
+#define __KSYMTAB_ENTRY_NS(sym, sec, ns) \
+ __ADDRESSABLE(sym) \
+ asm(" .section \"___ksymtab" sec "+" #sym "\", \"a\" \n" \
+ " .balign 4 \n" \
+ "__ksymtab_" #sym NS_SEPARATOR #ns ": \n" \
+ " .long " #sym "- . \n" \
+ " .long __kstrtab_" #sym "- . \n" \
+ " .long __kstrtab_ns_" #sym "- . \n" \
+ " .previous \n")
+
#define __KSYMTAB_ENTRY(sym, sec) \
__ADDRESSABLE(sym) \
asm(" .section \"___ksymtab" sec "+" #sym "\", \"a\" \n" \
@@ -56,32 +68,53 @@ extern struct module __this_module;
"__ksymtab_" #sym ": \n" \
" .long " #sym "- . \n" \
" .long __kstrtab_" #sym "- . \n" \
+ " .long 0 - . \n" \
" .previous \n")
struct kernel_symbol {
int value_offset;
int name_offset;
+ int namespace_offset;
};
#else
+#define __KSYMTAB_ENTRY_NS(sym, sec, ns) \
+ static const struct kernel_symbol __ksymtab_##sym##__##ns \
+ asm("__ksymtab_" #sym NS_SEPARATOR #ns) \
+ __attribute__((section("___ksymtab" sec "+" #sym), used)) \
+ __aligned(sizeof(void *)) \
+ = { (unsigned long)&sym, __kstrtab_##sym, __kstrtab_ns_##sym }
+
#define __KSYMTAB_ENTRY(sym, sec) \
static const struct kernel_symbol __ksymtab_##sym \
+ asm("__ksymtab_" #sym) \
__attribute__((section("___ksymtab" sec "+" #sym), used)) \
__aligned(sizeof(void *)) \
- = { (unsigned long)&sym, __kstrtab_##sym }
+ = { (unsigned long)&sym, __kstrtab_##sym, NULL }
struct kernel_symbol {
unsigned long value;
const char *name;
+ const char *namespace;
};
#endif
-/* For every exported symbol, place a struct in the __ksymtab section */
-#define ___EXPORT_SYMBOL(sym, sec) \
+#define ___export_symbol_common(sym, sec) \
extern typeof(sym) sym; \
- __CRC_SYMBOL(sym, sec) \
+ __CRC_SYMBOL(sym, sec); \
static const char __kstrtab_##sym[] \
__attribute__((section("__ksymtab_strings"), used, aligned(1))) \
- = #sym; \
+ = #sym \
+
+/* For every exported symbol, place a struct in the __ksymtab section */
+#define ___EXPORT_SYMBOL_NS(sym, sec, ns) \
+ ___export_symbol_common(sym, sec); \
+ static const char __kstrtab_ns_##sym[] \
+ __attribute__((section("__ksymtab_strings"), used, aligned(1))) \
+ = #ns; \
+ __KSYMTAB_ENTRY_NS(sym, sec, ns)
+
+#define ___EXPORT_SYMBOL(sym, sec) \
+ ___export_symbol_common(sym, sec); \
__KSYMTAB_ENTRY(sym, sec)
#if defined(__DISABLE_EXPORTS)
@@ -91,6 +124,7 @@ struct kernel_symbol {
* be reused in other execution contexts such as the UEFI stub or the
* decompressor.
*/
+#define __EXPORT_SYMBOL_NS(sym, sec, ns)
#define __EXPORT_SYMBOL(sym, sec)
#elif defined(CONFIG_TRIM_UNUSED_KSYMS)
@@ -117,18 +151,26 @@ struct kernel_symbol {
#define __cond_export_sym_1(sym, sec) ___EXPORT_SYMBOL(sym, sec)
#define __cond_export_sym_0(sym, sec) /* nothing */
+#define __EXPORT_SYMBOL_NS(sym, sec, ns) \
+ __ksym_marker(sym); \
+ __cond_export_ns_sym(sym, sec, ns, __is_defined(__KSYM_##sym))
+#define __cond_export_ns_sym(sym, sec, ns, conf) \
+ ___cond_export_ns_sym(sym, sec, ns, conf)
+#define ___cond_export_ns_sym(sym, sec, ns, enabled) \
+ __cond_export_ns_sym_##enabled(sym, sec, ns)
+#define __cond_export_ns_sym_1(sym, sec, ns) ___EXPORT_SYMBOL_NS(sym, sec, ns)
+#define __cond_export_ns_sym_0(sym, sec, ns) /* nothing */
+
#else
+#define __EXPORT_SYMBOL_NS ___EXPORT_SYMBOL_NS
#define __EXPORT_SYMBOL ___EXPORT_SYMBOL
#endif
-#define EXPORT_SYMBOL(sym) \
- __EXPORT_SYMBOL(sym, "")
-
-#define EXPORT_SYMBOL_GPL(sym) \
- __EXPORT_SYMBOL(sym, "_gpl")
-
-#define EXPORT_SYMBOL_GPL_FUTURE(sym) \
- __EXPORT_SYMBOL(sym, "_gpl_future")
+#define EXPORT_SYMBOL(sym) __EXPORT_SYMBOL(sym, "")
+#define EXPORT_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_gpl")
+#define EXPORT_SYMBOL_GPL_FUTURE(sym) __EXPORT_SYMBOL(sym, "_gpl_future")
+#define EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL_NS(sym, "", ns)
+#define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL_NS(sym, "_gpl", ns)
#ifdef CONFIG_UNUSED_SYMBOLS
#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
@@ -138,11 +180,28 @@ struct kernel_symbol {
#define EXPORT_UNUSED_SYMBOL_GPL(sym)
#endif
-#endif /* __GENKSYMS__ */
+#endif /* __KERNEL__ && !__GENKSYMS__ */
+
+#if defined(__GENKSYMS__)
+/*
+ * When we're running genksyms, ignore the namespace and make the _NS
+ * variants look like the normal ones. There are two reasons for this:
+ * 1) In the normal definition of EXPORT_SYMBOL_NS, the 'ns' macro
+ * argument is itself not expanded because it's always tokenized or
+ * concatenated; but when running genksyms, a blank definition of the
+ * macro does allow the argument to be expanded; if a namespace
+ * happens to collide with a #define, this can cause issues.
+ * 2) There's no need to modify genksyms to deal with the _NS variants
+ */
+#define EXPORT_SYMBOL_NS(sym, ns) EXPORT_SYMBOL(sym)
+#define EXPORT_SYMBOL_NS_GPL(sym, ns) EXPORT_SYMBOL_GPL(sym)
+#endif
#else /* !CONFIG_MODULES... */
#define EXPORT_SYMBOL(sym)
+#define EXPORT_SYMBOL_NS(sym, ns)
+#define EXPORT_SYMBOL_NS_GPL(sym, ns)
#define EXPORT_SYMBOL_GPL(sym)
#define EXPORT_SYMBOL_GPL_FUTURE(sym)
#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;
#ifdef CONFIG_MODULES
+#define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns)
+
extern int modules_disabled; /* for sysctl */
/* Get/put a kernel symbol (calls must be symmetric) */
void *__symbol_get(const char *symbol);