forked from Minki/linux
Modules updates for v5.12
Summary of modules changes for the 5.12 merge window: - Retire EXPORT_UNUSED_SYMBOL() and EXPORT_SYMBOL_GPL_FUTURE(). These export types were introduced between 2006 - 2008. All the of the unused symbols have been long removed and gpl future symbols were converted to gpl quite a long time ago, and I don't believe these export types have been used ever since. So, I think it should be safe to retire those export types now. (Christoph Hellwig) - Refactor and clean up some aged code cruft in the module loader (Christoph Hellwig) - Build {,module_}kallsyms_on_each_symbol only when livepatching is enabled, as it is the only caller (Christoph Hellwig) - Unexport find_module() and module_mutex and fix the last module callers to not rely on these anymore. Make module_mutex internal to the module loader. (Christoph Hellwig) - Harden ELF checks on module load and validate ELF structures before checking the module signature (Frank van der Linden) - Fix undefined symbol warning for clang (Fangrui Song) - Fix smatch warning (Dan Carpenter) Signed-off-by: Jessica Yu <jeyu@kernel.org> -----BEGIN PGP SIGNATURE----- iQJEBAABCAAuFiEEVrp26glSWYuDNrCUwEV+OM47wXIFAmA0/KMQHGpleXVAa2Vy bmVsLm9yZwAKCRDARX44zjvBcu0uD/4nmRp18EKAtdUZivsZHat0aEWGlkmrVueY 5huYw6iwM8b/wIAl3xwLki1Iv0/l0a83WXZhLG4ekl0/Nj8kgllA+jtBrZWpoLMH CZusN5dS9YwwyD2vu3ak83ARcehcDEPeA9thvc3uRFGis6Hi4bt1rkzGdrzsgqR4 tybfN4qaQx4ZAKFxA8bnS58l7QTFwUzTxJfM6WWzl1Q+mLZDr/WP+loJ/f1/oFFg ufN31KrqqFpdQY5UKq5P4H8FVq/eXE1Mwl8vo3HsnAj598fznyPUmA3D/j+N4GuR sTGBVZ9CSehUj7uZRs+Qgg6Bd+y3o44N29BrdZWA6K3ieTeQQpA+VgPUNrDBjGhP J/9Y4ms4PnuNEWWRaa73m9qsVqAsjh9+T2xp9PYn9uWLCM8BvQFtWcY7tw4/nB0/ INmyiP/tIRpwWkkBl47u1TPR09FzBBGDZjBiSn3lm3VX+zCYtHoma5jWyejG11cf ybDrTsci9ANyHNP2zFQsUOQJkph78PIal0i3k4ODqGJvaC0iEIH3Xjv+0dmE14rq kGRrG/HN6HhMZPjashudVUktyTZ63+PJpfFlQbcUzdvjQQIkzW0vrCHMWx9vD1xl Na7vZLl4Nb03WSJp6saY6j2YSRKL0poGETzGqrsUAHEhpEOPHduaiCVlAr/EmeMk p6SrWv8+UQ== =T29Q -----END PGP SIGNATURE----- Merge tag 'modules-for-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux Pull module updates from Jessica Yu: - Retire EXPORT_UNUSED_SYMBOL() and EXPORT_SYMBOL_GPL_FUTURE(). These export types were introduced between 2006 - 2008. All the of the unused symbols have been long removed and gpl future symbols were converted to gpl quite a long time ago, and I don't believe these export types have been used ever since. So, I think it should be safe to retire those export types now (Christoph Hellwig) - Refactor and clean up some aged code cruft in the module loader (Christoph Hellwig) - Build {,module_}kallsyms_on_each_symbol only when livepatching is enabled, as it is the only caller (Christoph Hellwig) - Unexport find_module() and module_mutex and fix the last module callers to not rely on these anymore. Make module_mutex internal to the module loader (Christoph Hellwig) - Harden ELF checks on module load and validate ELF structures before checking the module signature (Frank van der Linden) - Fix undefined symbol warning for clang (Fangrui Song) - Fix smatch warning (Dan Carpenter) * tag 'modules-for-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux: module: potential uninitialized return in module_kallsyms_on_each_symbol() module: remove EXPORT_UNUSED_SYMBOL* module: remove EXPORT_SYMBOL_GPL_FUTURE module: move struct symsearch to module.c module: pass struct find_symbol_args to find_symbol module: merge each_symbol_section into find_symbol module: remove each_symbol_in_section module: mark module_mutex static kallsyms: only build {,module_}kallsyms_on_each_symbol when required kallsyms: refactor {,module_}kallsyms_on_each_symbol module: use RCU to synchronize find_module module: unexport find_module and module_mutex drm: remove drm_fb_helper_modinit powerpc/powernv: remove get_cxl_module module: harden ELF info handling module: Ignore _GLOBAL_OFFSET_TABLE_ when warning for undefined symbols
This commit is contained in:
commit
21a6ab2131
@ -176,7 +176,6 @@ CONFIG_BOOT_PRINTK_DELAY=y
|
||||
CONFIG_DYNAMIC_DEBUG=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
# CONFIG_ENABLE_MUST_CHECK is not set
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
CONFIG_DEBUG_MEMORY_INIT=y
|
||||
CONFIG_LOCKUP_DETECTOR=y
|
||||
CONFIG_SCHED_TRACER=y
|
||||
|
@ -164,7 +164,6 @@ CONFIG_FONTS=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_FRAME_WARN=2048
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_DEBUG_KERNEL=y
|
||||
CONFIG_SOFTLOCKUP_DETECTOR=y
|
||||
|
@ -549,7 +549,6 @@ CONFIG_PRINTK_TIME=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
# CONFIG_ENABLE_MUST_CHECK is not set
|
||||
CONFIG_FRAME_WARN=1024
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
CONFIG_DEBUG_MEMORY_INIT=y
|
||||
CONFIG_DETECT_HUNG_TASK=y
|
||||
CONFIG_SCHEDSTATS=y
|
||||
|
@ -500,7 +500,6 @@ CONFIG_CRC7=m
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
# CONFIG_ENABLE_MUST_CHECK is not set
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
CONFIG_DEBUG_MEMORY_INIT=y
|
||||
CONFIG_DETECT_HUNG_TASK=y
|
||||
CONFIG_SCHEDSTATS=y
|
||||
|
@ -22,7 +22,6 @@ CONFIG_PCI_LBA=y
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
CONFIG_MODULE_FORCE_UNLOAD=y
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
CONFIG_BINFMT_MISC=m
|
||||
|
@ -31,7 +31,6 @@ CONFIG_MODULE_FORCE_LOAD=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
CONFIG_MODULE_FORCE_UNLOAD=y
|
||||
CONFIG_MODVERSIONS=y
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
CONFIG_BLK_DEV_INTEGRITY=y
|
||||
CONFIG_BINFMT_MISC=m
|
||||
# CONFIG_COMPACTION is not set
|
||||
|
@ -1071,7 +1071,6 @@ CONFIG_NLS_ISO8859_15=m
|
||||
CONFIG_NLS_KOI8_R=m
|
||||
CONFIG_NLS_KOI8_U=m
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
CONFIG_HEADERS_INSTALL=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_DEBUG_KERNEL=y
|
||||
|
@ -150,25 +150,3 @@ int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq,
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(pnv_cxl_ioda_msi_setup);
|
||||
|
||||
#if IS_MODULE(CONFIG_CXL)
|
||||
static inline int get_cxl_module(void)
|
||||
{
|
||||
struct module *cxl_module;
|
||||
|
||||
mutex_lock(&module_mutex);
|
||||
|
||||
cxl_module = find_module("cxl");
|
||||
if (cxl_module)
|
||||
__module_get(cxl_module);
|
||||
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
if (!cxl_module)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int get_cxl_module(void) { return 0; }
|
||||
#endif
|
||||
|
@ -71,7 +71,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
|
||||
CONFIG_MODVERSIONS=y
|
||||
CONFIG_MODULE_SRCVERSION_ALL=y
|
||||
CONFIG_MODULE_SIG_SHA256=y
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
CONFIG_BLK_DEV_INTEGRITY=y
|
||||
CONFIG_BLK_DEV_THROTTLING=y
|
||||
CONFIG_BLK_WBT=y
|
||||
|
@ -66,7 +66,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
|
||||
CONFIG_MODVERSIONS=y
|
||||
CONFIG_MODULE_SRCVERSION_ALL=y
|
||||
CONFIG_MODULE_SIG_SHA256=y
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
CONFIG_BLK_DEV_THROTTLING=y
|
||||
CONFIG_BLK_WBT=y
|
||||
CONFIG_BLK_CGROUP_IOLATENCY=y
|
||||
|
@ -102,7 +102,6 @@ CONFIG_NLS_UTF8=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
# CONFIG_ENABLE_MUST_CHECK is not set
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
CONFIG_DEBUG_KERNEL=y
|
||||
CONFIG_DEBUG_SHIRQ=y
|
||||
CONFIG_DETECT_HUNG_TASK=y
|
||||
|
@ -128,7 +128,6 @@ CONFIG_NLS_ISO8859_15=y
|
||||
CONFIG_NLS_UTF8=y
|
||||
# CONFIG_ENABLE_MUST_CHECK is not set
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
CONFIG_DEBUG_KERNEL=y
|
||||
CONFIG_DETECT_HUNG_TASK=y
|
||||
# CONFIG_SCHED_DEBUG is not set
|
||||
|
@ -50,7 +50,6 @@ CONFIG_JUMP_LABEL=y
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
CONFIG_MODULE_FORCE_UNLOAD=y
|
||||
# CONFIG_UNUSED_SYMBOLS is not set
|
||||
CONFIG_BINFMT_MISC=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
@ -48,7 +48,6 @@ CONFIG_JUMP_LABEL=y
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
CONFIG_MODULE_FORCE_UNLOAD=y
|
||||
# CONFIG_UNUSED_SYMBOLS is not set
|
||||
CONFIG_BINFMT_MISC=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
@ -61,8 +61,8 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
|
||||
"(__iommu_table|__apicdrivers|__smp_locks)(|_end)|"
|
||||
"__(start|end)_pci_.*|"
|
||||
"__(start|end)_builtin_fw|"
|
||||
"__(start|stop)___ksymtab(|_gpl|_unused|_unused_gpl|_gpl_future)|"
|
||||
"__(start|stop)___kcrctab(|_gpl|_unused|_unused_gpl|_gpl_future)|"
|
||||
"__(start|stop)___ksymtab(|_gpl)|"
|
||||
"__(start|stop)___kcrctab(|_gpl)|"
|
||||
"__(start|stop)___param|"
|
||||
"__(start|stop)___modver|"
|
||||
"__(start|stop)___bug_table|"
|
||||
|
@ -32,16 +32,6 @@
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_modes.h>
|
||||
|
||||
/* drm_fb_helper.c */
|
||||
#ifdef CONFIG_DRM_FBDEV_EMULATION
|
||||
int drm_fb_helper_modinit(void);
|
||||
#else
|
||||
static inline int drm_fb_helper_modinit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* drm_dp_aux_dev.c */
|
||||
#ifdef CONFIG_DRM_DP_AUX_CHARDEV
|
||||
int drm_dp_aux_dev_init(void);
|
||||
|
@ -2514,24 +2514,3 @@ void drm_fbdev_generic_setup(struct drm_device *dev,
|
||||
drm_client_register(&fb_helper->client);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fbdev_generic_setup);
|
||||
|
||||
/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
|
||||
* but the module doesn't depend on any fb console symbols. At least
|
||||
* attempt to load fbcon to avoid leaving the system without a usable console.
|
||||
*/
|
||||
int __init drm_fb_helper_modinit(void)
|
||||
{
|
||||
#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
|
||||
const char name[] = "fbcon";
|
||||
struct module *fbcon;
|
||||
|
||||
mutex_lock(&module_mutex);
|
||||
fbcon = find_module(name);
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
if (!fbcon)
|
||||
request_module_nowait(name);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_modinit);
|
||||
|
@ -64,19 +64,18 @@ MODULE_PARM_DESC(edid_firmware,
|
||||
|
||||
static int __init drm_kms_helper_init(void)
|
||||
{
|
||||
int ret;
|
||||
/*
|
||||
* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
|
||||
* but the module doesn't depend on any fb console symbols. At least
|
||||
* attempt to load fbcon to avoid leaving the system without a usable
|
||||
* console.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) &&
|
||||
IS_MODULE(CONFIG_FRAMEBUFFER_CONSOLE) &&
|
||||
!IS_ENABLED(CONFIG_EXPERT))
|
||||
request_module_nowait("fbcon");
|
||||
|
||||
/* Call init functions from specific kms helpers here */
|
||||
ret = drm_fb_helper_modinit();
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = drm_dp_aux_dev_init();
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
return drm_dp_aux_dev_init();
|
||||
}
|
||||
|
||||
static void __exit drm_kms_helper_exit(void)
|
||||
|
@ -497,27 +497,6 @@
|
||||
__stop___ksymtab_gpl = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: Normal unused symbols */ \
|
||||
__ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \
|
||||
__start___ksymtab_unused = .; \
|
||||
KEEP(*(SORT(___ksymtab_unused+*))) \
|
||||
__stop___ksymtab_unused = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-only unused symbols */ \
|
||||
__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
|
||||
__start___ksymtab_unused_gpl = .; \
|
||||
KEEP(*(SORT(___ksymtab_unused_gpl+*))) \
|
||||
__stop___ksymtab_unused_gpl = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-future-only symbols */ \
|
||||
__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
|
||||
__start___ksymtab_gpl_future = .; \
|
||||
KEEP(*(SORT(___ksymtab_gpl_future+*))) \
|
||||
__stop___ksymtab_gpl_future = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: Normal symbols */ \
|
||||
__kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \
|
||||
__start___kcrctab = .; \
|
||||
@ -532,27 +511,6 @@
|
||||
__stop___kcrctab_gpl = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: Normal unused symbols */ \
|
||||
__kcrctab_unused : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) { \
|
||||
__start___kcrctab_unused = .; \
|
||||
KEEP(*(SORT(___kcrctab_unused+*))) \
|
||||
__stop___kcrctab_unused = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-only unused symbols */ \
|
||||
__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
|
||||
__start___kcrctab_unused_gpl = .; \
|
||||
KEEP(*(SORT(___kcrctab_unused_gpl+*))) \
|
||||
__stop___kcrctab_unused_gpl = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-future-only symbols */ \
|
||||
__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
|
||||
__start___kcrctab_gpl_future = .; \
|
||||
KEEP(*(SORT(___kcrctab_gpl_future+*))) \
|
||||
__stop___kcrctab_gpl_future = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: strings */ \
|
||||
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
|
||||
*(__ksymtab_strings) \
|
||||
|
@ -157,18 +157,9 @@ struct kernel_symbol {
|
||||
|
||||
#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(sym, "", #ns)
|
||||
#define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "_gpl", #ns)
|
||||
|
||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||
#define EXPORT_UNUSED_SYMBOL(sym) _EXPORT_SYMBOL(sym, "_unused")
|
||||
#define EXPORT_UNUSED_SYMBOL_GPL(sym) _EXPORT_SYMBOL(sym, "_unused_gpl")
|
||||
#else
|
||||
#define EXPORT_UNUSED_SYMBOL(sym)
|
||||
#define EXPORT_UNUSED_SYMBOL_GPL(sym)
|
||||
#endif
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
#endif /* _LINUX_EXPORT_H */
|
||||
|
@ -71,15 +71,14 @@ static inline void *dereference_symbol_descriptor(void *ptr)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
/* Lookup the address for a symbol. Returns 0 if not found. */
|
||||
unsigned long kallsyms_lookup_name(const char *name);
|
||||
|
||||
/* Call a function on each kallsyms symbol in the core kernel */
|
||||
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
|
||||
unsigned long),
|
||||
void *data);
|
||||
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
/* Lookup the address for a symbol. Returns 0 if not found. */
|
||||
unsigned long kallsyms_lookup_name(const char *name);
|
||||
|
||||
extern int kallsyms_lookup_size_offset(unsigned long addr,
|
||||
unsigned long *symbolsize,
|
||||
unsigned long *offset);
|
||||
@ -108,14 +107,6 @@ static inline unsigned long kallsyms_lookup_name(const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int kallsyms_on_each_symbol(int (*fn)(void *, const char *,
|
||||
struct module *,
|
||||
unsigned long),
|
||||
void *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int kallsyms_lookup_size_offset(unsigned long addr,
|
||||
unsigned long *symbolsize,
|
||||
unsigned long *offset)
|
||||
|
@ -392,18 +392,6 @@ struct module {
|
||||
const s32 *gpl_crcs;
|
||||
bool using_gplonly_symbols;
|
||||
|
||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||
/* unused exported symbols. */
|
||||
const struct kernel_symbol *unused_syms;
|
||||
const s32 *unused_crcs;
|
||||
unsigned int num_unused_syms;
|
||||
|
||||
/* GPL-only, unused exported symbols. */
|
||||
unsigned int num_unused_gpl_syms;
|
||||
const struct kernel_symbol *unused_gpl_syms;
|
||||
const s32 *unused_gpl_crcs;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MODULE_SIG
|
||||
/* Signature was verified. */
|
||||
bool sig_ok;
|
||||
@ -411,11 +399,6 @@ struct module {
|
||||
|
||||
bool async_probe_requested;
|
||||
|
||||
/* symbols that will be GPL-only in the near future. */
|
||||
const struct kernel_symbol *gpl_future_syms;
|
||||
const s32 *gpl_future_crcs;
|
||||
unsigned int num_gpl_future_syms;
|
||||
|
||||
/* Exception table */
|
||||
unsigned int num_exentries;
|
||||
struct exception_table_entry *extable;
|
||||
@ -550,8 +533,6 @@ static inline unsigned long kallsyms_symbol_value(const Elf_Sym *sym)
|
||||
}
|
||||
#endif
|
||||
|
||||
extern struct mutex module_mutex;
|
||||
|
||||
/* FIXME: It'd be nice to isolate modules during init, too, so they
|
||||
aren't used before they (may) fail. But presently too much code
|
||||
(IDE & SCSI) require entry into the module during init.*/
|
||||
@ -586,20 +567,9 @@ static inline bool within_module(unsigned long addr, const struct module *mod)
|
||||
return within_module_init(addr, mod) || within_module_core(addr, mod);
|
||||
}
|
||||
|
||||
/* Search for module by name: must hold module_mutex. */
|
||||
/* Search for module by name: must be in a RCU-sched critical section. */
|
||||
struct module *find_module(const char *name);
|
||||
|
||||
struct symsearch {
|
||||
const struct kernel_symbol *start, *stop;
|
||||
const s32 *crcs;
|
||||
enum mod_license {
|
||||
NOT_GPL_ONLY,
|
||||
GPL_ONLY,
|
||||
WILL_BE_GPL_ONLY,
|
||||
} license;
|
||||
bool unused;
|
||||
};
|
||||
|
||||
/* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
|
||||
symnum out of range. */
|
||||
int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
|
||||
@ -608,10 +578,6 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
|
||||
/* Look for this name: can be of form module:name. */
|
||||
unsigned long module_kallsyms_lookup_name(const char *name);
|
||||
|
||||
int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
|
||||
struct module *, unsigned long),
|
||||
void *data);
|
||||
|
||||
extern void __noreturn __module_put_and_exit(struct module *mod,
|
||||
long code);
|
||||
#define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code)
|
||||
@ -795,14 +761,6 @@ static inline unsigned long module_kallsyms_lookup_name(const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
|
||||
struct module *,
|
||||
unsigned long),
|
||||
void *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int register_module_notifier(struct notifier_block *nb)
|
||||
{
|
||||
/* no events will happen anyway, so this can always succeed */
|
||||
@ -891,4 +849,8 @@ static inline bool module_sig_ok(struct module *module)
|
||||
}
|
||||
#endif /* CONFIG_MODULE_SIG */
|
||||
|
||||
int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
|
||||
struct module *, unsigned long),
|
||||
void *data);
|
||||
|
||||
#endif /* _LINUX_MODULE_H */
|
||||
|
17
init/Kconfig
17
init/Kconfig
@ -2272,25 +2272,8 @@ config MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config UNUSED_SYMBOLS
|
||||
bool "Enable unused/obsolete exported symbols"
|
||||
default y if X86
|
||||
help
|
||||
Unused but exported symbols make the kernel needlessly bigger. For
|
||||
that reason most of these unused exports will soon be removed. This
|
||||
option is provided temporarily to provide a transition period in case
|
||||
some external kernel module needs one of these symbols anyway. If you
|
||||
encounter such a case in your module, consider if you are actually
|
||||
using the right API. (rationale: since nobody in the kernel is using
|
||||
this in a module, there is a pretty good chance it's actually the
|
||||
wrong interface to use). If you really need the symbol, please send a
|
||||
mail to the linux kernel mailing list mentioning the symbol and why
|
||||
you really need it, and what the merge plan to the mainline kernel for
|
||||
your module is.
|
||||
|
||||
config TRIM_UNUSED_KSYMS
|
||||
bool "Trim unused exported kernel symbols"
|
||||
depends on !UNUSED_SYMBOLS
|
||||
help
|
||||
The kernel and some modules make many symbols available for
|
||||
other modules to use via EXPORT_SYMBOL() and variants. Depending
|
||||
|
@ -177,6 +177,11 @@ unsigned long kallsyms_lookup_name(const char *name)
|
||||
return module_kallsyms_lookup_name(name);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIVEPATCH
|
||||
/*
|
||||
* Iterate over all symbols in vmlinux. For symbols from modules use
|
||||
* module_kallsyms_on_each_symbol instead.
|
||||
*/
|
||||
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
|
||||
unsigned long),
|
||||
void *data)
|
||||
@ -192,8 +197,9 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
return module_kallsyms_on_each_symbol(fn, data);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_LIVEPATCH */
|
||||
|
||||
static unsigned long get_symbol_pos(unsigned long addr,
|
||||
unsigned long *symbolsize,
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/moduleloader.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/memory.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include "core.h"
|
||||
#include "patch.h"
|
||||
@ -57,7 +58,7 @@ static void klp_find_object_module(struct klp_object *obj)
|
||||
if (!klp_is_module(obj))
|
||||
return;
|
||||
|
||||
mutex_lock(&module_mutex);
|
||||
rcu_read_lock_sched();
|
||||
/*
|
||||
* We do not want to block removal of patched modules and therefore
|
||||
* we do not take a reference here. The patches are removed by
|
||||
@ -74,7 +75,7 @@ static void klp_find_object_module(struct klp_object *obj)
|
||||
if (mod && mod->klp_alive)
|
||||
obj->mod = mod;
|
||||
|
||||
mutex_unlock(&module_mutex);
|
||||
rcu_read_unlock_sched();
|
||||
}
|
||||
|
||||
static bool klp_initialized(void)
|
||||
@ -163,12 +164,10 @@ static int klp_find_object_symbol(const char *objname, const char *name,
|
||||
.pos = sympos,
|
||||
};
|
||||
|
||||
mutex_lock(&module_mutex);
|
||||
if (objname)
|
||||
module_kallsyms_on_each_symbol(klp_find_callback, &args);
|
||||
else
|
||||
kallsyms_on_each_symbol(klp_find_callback, &args);
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
/*
|
||||
* Ensure an address was found. If sympos is 0, ensure symbol is unique;
|
||||
|
473
kernel/module.c
473
kernel/module.c
@ -87,8 +87,7 @@
|
||||
* 3) module_addr_min/module_addr_max.
|
||||
* (delete and add uses RCU list operations).
|
||||
*/
|
||||
DEFINE_MUTEX(module_mutex);
|
||||
EXPORT_SYMBOL_GPL(module_mutex);
|
||||
static DEFINE_MUTEX(module_mutex);
|
||||
static LIST_HEAD(modules);
|
||||
|
||||
/* Work queue for freeing init sections in success case */
|
||||
@ -256,11 +255,6 @@ static void mod_update_bounds(struct module *mod)
|
||||
struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
|
||||
#endif /* CONFIG_KGDB_KDB */
|
||||
|
||||
static void module_assert_mutex(void)
|
||||
{
|
||||
lockdep_assert_held(&module_mutex);
|
||||
}
|
||||
|
||||
static void module_assert_mutex_or_preempt(void)
|
||||
{
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
@ -414,19 +408,8 @@ 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 struct kernel_symbol __start___ksymtab_gpl_future[];
|
||||
extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
|
||||
extern const s32 __start___kcrctab[];
|
||||
extern const s32 __start___kcrctab_gpl[];
|
||||
extern const s32 __start___kcrctab_gpl_future[];
|
||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||
extern const struct kernel_symbol __start___ksymtab_unused[];
|
||||
extern const struct kernel_symbol __stop___ksymtab_unused[];
|
||||
extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
|
||||
extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
|
||||
extern const s32 __start___kcrctab_unused[];
|
||||
extern const s32 __start___kcrctab_unused_gpl[];
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_MODVERSIONS
|
||||
#define symversion(base, idx) NULL
|
||||
@ -434,87 +417,14 @@ extern const s32 __start___kcrctab_unused_gpl[];
|
||||
#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
|
||||
#endif
|
||||
|
||||
static bool each_symbol_in_section(const struct symsearch *arr,
|
||||
unsigned int arrsize,
|
||||
struct module *owner,
|
||||
bool (*fn)(const struct symsearch *syms,
|
||||
struct module *owner,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
unsigned int j;
|
||||
|
||||
for (j = 0; j < arrsize; j++) {
|
||||
if (fn(&arr[j], owner, data))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Returns true as soon as fn returns true, otherwise false. */
|
||||
static bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
|
||||
struct module *owner,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
struct module *mod;
|
||||
static const struct symsearch arr[] = {
|
||||
{ __start___ksymtab, __stop___ksymtab, __start___kcrctab,
|
||||
NOT_GPL_ONLY, false },
|
||||
{ __start___ksymtab_gpl, __stop___ksymtab_gpl,
|
||||
__start___kcrctab_gpl,
|
||||
GPL_ONLY, false },
|
||||
{ __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future,
|
||||
__start___kcrctab_gpl_future,
|
||||
WILL_BE_GPL_ONLY, false },
|
||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||
{ __start___ksymtab_unused, __stop___ksymtab_unused,
|
||||
__start___kcrctab_unused,
|
||||
NOT_GPL_ONLY, true },
|
||||
{ __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl,
|
||||
__start___kcrctab_unused_gpl,
|
||||
GPL_ONLY, true },
|
||||
#endif
|
||||
};
|
||||
|
||||
module_assert_mutex_or_preempt();
|
||||
|
||||
if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data))
|
||||
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, false },
|
||||
{ mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
|
||||
mod->gpl_crcs,
|
||||
GPL_ONLY, false },
|
||||
{ mod->gpl_future_syms,
|
||||
mod->gpl_future_syms + mod->num_gpl_future_syms,
|
||||
mod->gpl_future_crcs,
|
||||
WILL_BE_GPL_ONLY, false },
|
||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||
{ mod->unused_syms,
|
||||
mod->unused_syms + mod->num_unused_syms,
|
||||
mod->unused_crcs,
|
||||
NOT_GPL_ONLY, true },
|
||||
{ mod->unused_gpl_syms,
|
||||
mod->unused_gpl_syms + mod->num_unused_gpl_syms,
|
||||
mod->unused_gpl_crcs,
|
||||
GPL_ONLY, true },
|
||||
#endif
|
||||
};
|
||||
|
||||
if (mod->state == MODULE_STATE_UNFORMED)
|
||||
continue;
|
||||
|
||||
if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
struct symsearch {
|
||||
const struct kernel_symbol *start, *stop;
|
||||
const s32 *crcs;
|
||||
enum mod_license {
|
||||
NOT_GPL_ONLY,
|
||||
GPL_ONLY,
|
||||
} license;
|
||||
};
|
||||
|
||||
struct find_symbol_arg {
|
||||
/* Input */
|
||||
@ -535,28 +445,8 @@ static bool check_exported_symbol(const struct symsearch *syms,
|
||||
{
|
||||
struct find_symbol_arg *fsa = data;
|
||||
|
||||
if (!fsa->gplok) {
|
||||
if (syms->license == GPL_ONLY)
|
||||
return false;
|
||||
if (syms->license == WILL_BE_GPL_ONLY && fsa->warn) {
|
||||
pr_warn("Symbol %s is being used by a non-GPL module, "
|
||||
"which will not be allowed in the future\n",
|
||||
fsa->name);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||
if (syms->unused && fsa->warn) {
|
||||
pr_warn("Symbol %s is marked as UNUSED, however this module is "
|
||||
"using it.\n", fsa->name);
|
||||
pr_warn("This symbol will go away in the future.\n");
|
||||
pr_warn("Please evaluate if this is the right api to use and "
|
||||
"if it really is, submit a report to the linux kernel "
|
||||
"mailing list together with submitting your code for "
|
||||
"inclusion.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!fsa->gplok && syms->license == GPL_ONLY)
|
||||
return false;
|
||||
fsa->owner = owner;
|
||||
fsa->crc = symversion(syms->crcs, symnum);
|
||||
fsa->sym = &syms->start[symnum];
|
||||
@ -619,31 +509,44 @@ static bool find_exported_symbol_in_section(const struct symsearch *syms,
|
||||
* Find an exported symbol and return it, along with, (optional) crc and
|
||||
* (optional) module which owns it. Needs preempt disabled or module_mutex.
|
||||
*/
|
||||
static const struct kernel_symbol *find_symbol(const char *name,
|
||||
struct module **owner,
|
||||
const s32 **crc,
|
||||
enum mod_license *license,
|
||||
bool gplok,
|
||||
bool warn)
|
||||
static bool find_symbol(struct find_symbol_arg *fsa)
|
||||
{
|
||||
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 },
|
||||
};
|
||||
struct module *mod;
|
||||
unsigned int i;
|
||||
|
||||
fsa.name = name;
|
||||
fsa.gplok = gplok;
|
||||
fsa.warn = warn;
|
||||
module_assert_mutex_or_preempt();
|
||||
|
||||
if (each_symbol_section(find_exported_symbol_in_section, &fsa)) {
|
||||
if (owner)
|
||||
*owner = fsa.owner;
|
||||
if (crc)
|
||||
*crc = fsa.crc;
|
||||
if (license)
|
||||
*license = fsa.license;
|
||||
return fsa.sym;
|
||||
for (i = 0; i < ARRAY_SIZE(arr); i++)
|
||||
if (find_exported_symbol_in_section(&arr[i], 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 },
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
pr_debug("Failed to find symbol %s\n", name);
|
||||
return NULL;
|
||||
pr_debug("Failed to find symbol %s\n", fsa->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -669,10 +572,8 @@ static struct module *find_module_all(const char *name, size_t len,
|
||||
|
||||
struct module *find_module(const char *name)
|
||||
{
|
||||
module_assert_mutex();
|
||||
return find_module_all(name, strlen(name), false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(find_module);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
@ -1107,12 +1008,15 @@ static inline void print_unload_info(struct seq_file *m, struct module *mod)
|
||||
|
||||
void __symbol_put(const char *symbol)
|
||||
{
|
||||
struct module *owner;
|
||||
struct find_symbol_arg fsa = {
|
||||
.name = symbol,
|
||||
.gplok = true,
|
||||
};
|
||||
|
||||
preempt_disable();
|
||||
if (!find_symbol(symbol, &owner, NULL, NULL, true, false))
|
||||
if (!find_symbol(&fsa))
|
||||
BUG();
|
||||
module_put(owner);
|
||||
module_put(fsa.owner);
|
||||
preempt_enable();
|
||||
}
|
||||
EXPORT_SYMBOL(__symbol_put);
|
||||
@ -1381,19 +1285,22 @@ bad_version:
|
||||
static inline int check_modstruct_version(const struct load_info *info,
|
||||
struct module *mod)
|
||||
{
|
||||
const s32 *crc;
|
||||
struct find_symbol_arg fsa = {
|
||||
.name = "module_layout",
|
||||
.gplok = true,
|
||||
};
|
||||
|
||||
/*
|
||||
* Since this should be found in kernel (which can't be removed), no
|
||||
* locking is necessary -- use preempt_disable() to placate lockdep.
|
||||
*/
|
||||
preempt_disable();
|
||||
if (!find_symbol("module_layout", NULL, &crc, NULL, true, false)) {
|
||||
if (!find_symbol(&fsa)) {
|
||||
preempt_enable();
|
||||
BUG();
|
||||
}
|
||||
preempt_enable();
|
||||
return check_version(info, "module_layout", mod, crc);
|
||||
return check_version(info, "module_layout", mod, fsa.crc);
|
||||
}
|
||||
|
||||
/* First part is kernel version, which we ignore if module has crcs. */
|
||||
@ -1487,10 +1394,11 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
|
||||
const char *name,
|
||||
char ownername[])
|
||||
{
|
||||
struct module *owner;
|
||||
const struct kernel_symbol *sym;
|
||||
const s32 *crc;
|
||||
enum mod_license license;
|
||||
struct find_symbol_arg fsa = {
|
||||
.name = name,
|
||||
.gplok = !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)),
|
||||
.warn = true,
|
||||
};
|
||||
int err;
|
||||
|
||||
/*
|
||||
@ -1500,42 +1408,40 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
|
||||
*/
|
||||
sched_annotate_sleep();
|
||||
mutex_lock(&module_mutex);
|
||||
sym = find_symbol(name, &owner, &crc, &license,
|
||||
!(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true);
|
||||
if (!sym)
|
||||
if (!find_symbol(&fsa))
|
||||
goto unlock;
|
||||
|
||||
if (license == GPL_ONLY)
|
||||
if (fsa.license == GPL_ONLY)
|
||||
mod->using_gplonly_symbols = true;
|
||||
|
||||
if (!inherit_taint(mod, owner)) {
|
||||
sym = NULL;
|
||||
if (!inherit_taint(mod, fsa.owner)) {
|
||||
fsa.sym = NULL;
|
||||
goto getname;
|
||||
}
|
||||
|
||||
if (!check_version(info, name, mod, crc)) {
|
||||
sym = ERR_PTR(-EINVAL);
|
||||
if (!check_version(info, name, mod, fsa.crc)) {
|
||||
fsa.sym = ERR_PTR(-EINVAL);
|
||||
goto getname;
|
||||
}
|
||||
|
||||
err = verify_namespace_is_imported(info, sym, mod);
|
||||
err = verify_namespace_is_imported(info, fsa.sym, mod);
|
||||
if (err) {
|
||||
sym = ERR_PTR(err);
|
||||
fsa.sym = ERR_PTR(err);
|
||||
goto getname;
|
||||
}
|
||||
|
||||
err = ref_module(mod, owner);
|
||||
err = ref_module(mod, fsa.owner);
|
||||
if (err) {
|
||||
sym = ERR_PTR(err);
|
||||
fsa.sym = ERR_PTR(err);
|
||||
goto getname;
|
||||
}
|
||||
|
||||
getname:
|
||||
/* We must make copy under the lock if we failed to get ref. */
|
||||
strncpy(ownername, module_name(owner), MODULE_NAME_LEN);
|
||||
strncpy(ownername, module_name(fsa.owner), MODULE_NAME_LEN);
|
||||
unlock:
|
||||
mutex_unlock(&module_mutex);
|
||||
return sym;
|
||||
return fsa.sym;
|
||||
}
|
||||
|
||||
static const struct kernel_symbol *
|
||||
@ -2296,16 +2202,19 @@ static void free_module(struct module *mod)
|
||||
|
||||
void *__symbol_get(const char *symbol)
|
||||
{
|
||||
struct module *owner;
|
||||
const struct kernel_symbol *sym;
|
||||
struct find_symbol_arg fsa = {
|
||||
.name = symbol,
|
||||
.gplok = true,
|
||||
.warn = true,
|
||||
};
|
||||
|
||||
preempt_disable();
|
||||
sym = find_symbol(symbol, &owner, NULL, NULL, true, true);
|
||||
if (sym && strong_try_module_get(owner))
|
||||
sym = NULL;
|
||||
if (!find_symbol(&fsa) || strong_try_module_get(fsa.owner)) {
|
||||
preempt_enable();
|
||||
return NULL;
|
||||
}
|
||||
preempt_enable();
|
||||
|
||||
return sym ? (void *)kernel_symbol_value(sym) : NULL;
|
||||
return (void *)kernel_symbol_value(fsa.sym);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__symbol_get);
|
||||
|
||||
@ -2318,7 +2227,6 @@ EXPORT_SYMBOL_GPL(__symbol_get);
|
||||
static int verify_exported_symbols(struct module *mod)
|
||||
{
|
||||
unsigned int i;
|
||||
struct module *owner;
|
||||
const struct kernel_symbol *s;
|
||||
struct {
|
||||
const struct kernel_symbol *sym;
|
||||
@ -2326,21 +2234,19 @@ static int verify_exported_symbols(struct module *mod)
|
||||
} arr[] = {
|
||||
{ mod->syms, mod->num_syms },
|
||||
{ mod->gpl_syms, mod->num_gpl_syms },
|
||||
{ mod->gpl_future_syms, mod->num_gpl_future_syms },
|
||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||
{ mod->unused_syms, mod->num_unused_syms },
|
||||
{ mod->unused_gpl_syms, mod->num_unused_gpl_syms },
|
||||
#endif
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(arr); i++) {
|
||||
for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
|
||||
if (find_symbol(kernel_symbol_name(s), &owner, NULL,
|
||||
NULL, true, false)) {
|
||||
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(owner));
|
||||
module_name(fsa.owner));
|
||||
return -ENOEXEC;
|
||||
}
|
||||
}
|
||||
@ -2348,6 +2254,21 @@ static int verify_exported_symbols(struct module *mod)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ignore_undef_symbol(Elf_Half emachine, const char *name)
|
||||
{
|
||||
/*
|
||||
* On x86, PIC code and Clang non-PIC code may have call foo@PLT. GNU as
|
||||
* before 2.37 produces an unreferenced _GLOBAL_OFFSET_TABLE_ on x86-64.
|
||||
* i386 has a similar problem but may not deserve a fix.
|
||||
*
|
||||
* If we ever have to ignore many symbols, consider refactoring the code to
|
||||
* only warn if referenced by a relocation.
|
||||
*/
|
||||
if (emachine == EM_386 || emachine == EM_X86_64)
|
||||
return !strcmp(name, "_GLOBAL_OFFSET_TABLE_");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Change all symbols so that st_value encodes the pointer directly. */
|
||||
static int simplify_symbols(struct module *mod, const struct load_info *info)
|
||||
{
|
||||
@ -2395,8 +2316,10 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Ok if weak. */
|
||||
if (!ksym && ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
|
||||
/* Ok if weak or ignored. */
|
||||
if (!ksym &&
|
||||
(ELF_ST_BIND(sym[i].st_info) == STB_WEAK ||
|
||||
ignore_undef_symbol(info->hdr->e_machine, name)))
|
||||
break;
|
||||
|
||||
ret = PTR_ERR(ksym) ?: -ENOENT;
|
||||
@ -2964,7 +2887,7 @@ static int module_sig_check(struct load_info *info, int flags)
|
||||
}
|
||||
|
||||
if (is_module_sig_enforced()) {
|
||||
pr_notice("%s: loading of %s is rejected\n", info->name, reason);
|
||||
pr_notice("Loading of %s is rejected\n", reason);
|
||||
return -EKEYREJECTED;
|
||||
}
|
||||
|
||||
@ -2977,9 +2900,33 @@ static int module_sig_check(struct load_info *info, int flags)
|
||||
}
|
||||
#endif /* !CONFIG_MODULE_SIG */
|
||||
|
||||
/* Sanity checks against invalid binaries, wrong arch, weird elf version. */
|
||||
static int elf_header_check(struct load_info *info)
|
||||
static int validate_section_offset(struct load_info *info, Elf_Shdr *shdr)
|
||||
{
|
||||
unsigned long secend;
|
||||
|
||||
/*
|
||||
* Check for both overflow and offset/size being
|
||||
* too large.
|
||||
*/
|
||||
secend = shdr->sh_offset + shdr->sh_size;
|
||||
if (secend < shdr->sh_offset || secend > info->len)
|
||||
return -ENOEXEC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity checks against invalid binaries, wrong arch, weird elf version.
|
||||
*
|
||||
* Also do basic validity checks against section offsets and sizes, the
|
||||
* section name string table, and the indices used for it (sh_name).
|
||||
*/
|
||||
static int elf_validity_check(struct load_info *info)
|
||||
{
|
||||
unsigned int i;
|
||||
Elf_Shdr *shdr, *strhdr;
|
||||
int err;
|
||||
|
||||
if (info->len < sizeof(*(info->hdr)))
|
||||
return -ENOEXEC;
|
||||
|
||||
@ -2989,11 +2936,78 @@ static int elf_header_check(struct load_info *info)
|
||||
|| info->hdr->e_shentsize != sizeof(Elf_Shdr))
|
||||
return -ENOEXEC;
|
||||
|
||||
/*
|
||||
* e_shnum is 16 bits, and sizeof(Elf_Shdr) is
|
||||
* known and small. So e_shnum * sizeof(Elf_Shdr)
|
||||
* will not overflow unsigned long on any platform.
|
||||
*/
|
||||
if (info->hdr->e_shoff >= info->len
|
||||
|| (info->hdr->e_shnum * sizeof(Elf_Shdr) >
|
||||
info->len - info->hdr->e_shoff))
|
||||
return -ENOEXEC;
|
||||
|
||||
info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
|
||||
|
||||
/*
|
||||
* Verify if the section name table index is valid.
|
||||
*/
|
||||
if (info->hdr->e_shstrndx == SHN_UNDEF
|
||||
|| info->hdr->e_shstrndx >= info->hdr->e_shnum)
|
||||
return -ENOEXEC;
|
||||
|
||||
strhdr = &info->sechdrs[info->hdr->e_shstrndx];
|
||||
err = validate_section_offset(info, strhdr);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* The section name table must be NUL-terminated, as required
|
||||
* by the spec. This makes strcmp and pr_* calls that access
|
||||
* strings in the section safe.
|
||||
*/
|
||||
info->secstrings = (void *)info->hdr + strhdr->sh_offset;
|
||||
if (info->secstrings[strhdr->sh_size - 1] != '\0')
|
||||
return -ENOEXEC;
|
||||
|
||||
/*
|
||||
* The code assumes that section 0 has a length of zero and
|
||||
* an addr of zero, so check for it.
|
||||
*/
|
||||
if (info->sechdrs[0].sh_type != SHT_NULL
|
||||
|| info->sechdrs[0].sh_size != 0
|
||||
|| info->sechdrs[0].sh_addr != 0)
|
||||
return -ENOEXEC;
|
||||
|
||||
for (i = 1; i < info->hdr->e_shnum; i++) {
|
||||
shdr = &info->sechdrs[i];
|
||||
switch (shdr->sh_type) {
|
||||
case SHT_NULL:
|
||||
case SHT_NOBITS:
|
||||
continue;
|
||||
case SHT_SYMTAB:
|
||||
if (shdr->sh_link == SHN_UNDEF
|
||||
|| shdr->sh_link >= info->hdr->e_shnum)
|
||||
return -ENOEXEC;
|
||||
fallthrough;
|
||||
default:
|
||||
err = validate_section_offset(info, shdr);
|
||||
if (err < 0) {
|
||||
pr_err("Invalid ELF section in module (section %u type %u)\n",
|
||||
i, shdr->sh_type);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (shdr->sh_flags & SHF_ALLOC) {
|
||||
if (shdr->sh_name >= strhdr->sh_size) {
|
||||
pr_err("Invalid ELF section name in module (section %u type %u)\n",
|
||||
i, shdr->sh_type);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3095,11 +3109,6 @@ static int rewrite_section_headers(struct load_info *info, int flags)
|
||||
|
||||
for (i = 1; i < info->hdr->e_shnum; i++) {
|
||||
Elf_Shdr *shdr = &info->sechdrs[i];
|
||||
if (shdr->sh_type != SHT_NOBITS
|
||||
&& info->len < shdr->sh_offset + shdr->sh_size) {
|
||||
pr_err("Module len %lu truncated\n", info->len);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark all sections sh_addr with their address in the
|
||||
@ -3133,11 +3142,6 @@ static int setup_load_info(struct load_info *info, int flags)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Set up the convenience variables */
|
||||
info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
|
||||
info->secstrings = (void *)info->hdr
|
||||
+ info->sechdrs[info->hdr->e_shstrndx].sh_offset;
|
||||
|
||||
/* Try to find a name early so we can log errors with a module name */
|
||||
info->index.info = find_sec(info, ".modinfo");
|
||||
if (info->index.info)
|
||||
@ -3241,22 +3245,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->gpl_future_syms = section_objs(info,
|
||||
"__ksymtab_gpl_future",
|
||||
sizeof(*mod->gpl_future_syms),
|
||||
&mod->num_gpl_future_syms);
|
||||
mod->gpl_future_crcs = section_addr(info, "__kcrctab_gpl_future");
|
||||
|
||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||
mod->unused_syms = section_objs(info, "__ksymtab_unused",
|
||||
sizeof(*mod->unused_syms),
|
||||
&mod->num_unused_syms);
|
||||
mod->unused_crcs = section_addr(info, "__kcrctab_unused");
|
||||
mod->unused_gpl_syms = section_objs(info, "__ksymtab_unused_gpl",
|
||||
sizeof(*mod->unused_gpl_syms),
|
||||
&mod->num_unused_gpl_syms);
|
||||
mod->unused_gpl_crcs = section_addr(info, "__kcrctab_unused_gpl");
|
||||
#endif
|
||||
#ifdef CONFIG_CONSTRUCTORS
|
||||
mod->ctors = section_objs(info, ".ctors",
|
||||
sizeof(*mod->ctors), &mod->num_ctors);
|
||||
@ -3437,14 +3426,8 @@ static int check_module_license_and_versions(struct module *mod)
|
||||
pr_warn("%s: module license taints kernel.\n", mod->name);
|
||||
|
||||
#ifdef CONFIG_MODVERSIONS
|
||||
if ((mod->num_syms && !mod->crcs)
|
||||
|| (mod->num_gpl_syms && !mod->gpl_crcs)
|
||||
|| (mod->num_gpl_future_syms && !mod->gpl_future_crcs)
|
||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||
|| (mod->num_unused_syms && !mod->unused_crcs)
|
||||
|| (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs)
|
||||
#endif
|
||||
) {
|
||||
if ((mod->num_syms && !mod->crcs) ||
|
||||
(mod->num_gpl_syms && !mod->gpl_crcs)) {
|
||||
return try_to_force_load(mod,
|
||||
"no versions for exported symbols");
|
||||
}
|
||||
@ -3894,26 +3877,50 @@ static int load_module(struct load_info *info, const char __user *uargs,
|
||||
long err = 0;
|
||||
char *after_dashes;
|
||||
|
||||
err = elf_header_check(info);
|
||||
/*
|
||||
* Do the signature check (if any) first. All that
|
||||
* the signature check needs is info->len, it does
|
||||
* not need any of the section info. That can be
|
||||
* set up later. This will minimize the chances
|
||||
* of a corrupt module causing problems before
|
||||
* we even get to the signature check.
|
||||
*
|
||||
* The check will also adjust info->len by stripping
|
||||
* off the sig length at the end of the module, making
|
||||
* checks against info->len more correct.
|
||||
*/
|
||||
err = module_sig_check(info, flags);
|
||||
if (err)
|
||||
goto free_copy;
|
||||
|
||||
/*
|
||||
* Do basic sanity checks against the ELF header and
|
||||
* sections.
|
||||
*/
|
||||
err = elf_validity_check(info);
|
||||
if (err) {
|
||||
pr_err("Module has invalid ELF header\n");
|
||||
pr_err("Module has invalid ELF structures\n");
|
||||
goto free_copy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Everything checks out, so set up the section info
|
||||
* in the info structure.
|
||||
*/
|
||||
err = setup_load_info(info, flags);
|
||||
if (err)
|
||||
goto free_copy;
|
||||
|
||||
/*
|
||||
* Now that we know we have the correct module name, check
|
||||
* if it's blacklisted.
|
||||
*/
|
||||
if (blacklisted(info->name)) {
|
||||
err = -EPERM;
|
||||
pr_err("Module %s is blacklisted\n", info->name);
|
||||
goto free_copy;
|
||||
}
|
||||
|
||||
err = module_sig_check(info, flags);
|
||||
if (err)
|
||||
goto free_copy;
|
||||
|
||||
err = rewrite_section_headers(info, flags);
|
||||
if (err)
|
||||
goto free_copy;
|
||||
@ -4374,16 +4381,16 @@ unsigned long module_kallsyms_lookup_name(const char *name)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIVEPATCH
|
||||
int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
|
||||
struct module *, unsigned long),
|
||||
void *data)
|
||||
{
|
||||
struct module *mod;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
module_assert_mutex();
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&module_mutex);
|
||||
list_for_each_entry(mod, &modules, list) {
|
||||
/* We hold module_mutex: no need for rcu_dereference_sched */
|
||||
struct mod_kallsyms *kallsyms = mod->kallsyms;
|
||||
@ -4399,11 +4406,13 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
|
||||
ret = fn(data, kallsyms_symbol_name(kallsyms, i),
|
||||
mod, kallsyms_symbol_value(sym));
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
mutex_unlock(&module_mutex);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_LIVEPATCH */
|
||||
#endif /* CONFIG_KALLSYMS */
|
||||
|
||||
/* Maximum number of characters written by module_flags() */
|
||||
|
@ -25,7 +25,7 @@ int mod_check_sig(const struct module_signature *ms, size_t file_len,
|
||||
return -EBADMSG;
|
||||
|
||||
if (ms->id_type != PKEY_ID_PKCS7) {
|
||||
pr_err("%s: Module is not signed with expected PKCS#7 message\n",
|
||||
pr_err("%s: not signed with expected PKCS#7 message\n",
|
||||
name);
|
||||
return -ENOPKG;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ int mod_verify_sig(const void *mod, struct load_info *info)
|
||||
|
||||
memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
|
||||
|
||||
ret = mod_check_sig(&ms, modlen, info->name);
|
||||
ret = mod_check_sig(&ms, modlen, "module");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -124,9 +124,9 @@ static nokprobe_inline bool trace_kprobe_module_exist(struct trace_kprobe *tk)
|
||||
if (!p)
|
||||
return true;
|
||||
*p = '\0';
|
||||
mutex_lock(&module_mutex);
|
||||
rcu_read_lock_sched();
|
||||
ret = !!find_module(tk->symbol);
|
||||
mutex_unlock(&module_mutex);
|
||||
rcu_read_unlock_sched();
|
||||
*p = ':';
|
||||
|
||||
return ret;
|
||||
|
@ -91,8 +91,6 @@ void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
|
||||
char *secstrings;
|
||||
unsigned int i;
|
||||
|
||||
lockdep_assert_held(&module_mutex);
|
||||
|
||||
mod->bug_table = NULL;
|
||||
mod->num_bugs = 0;
|
||||
|
||||
@ -118,7 +116,6 @@ void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
|
||||
|
||||
void module_bug_cleanup(struct module *mod)
|
||||
{
|
||||
lockdep_assert_held(&module_mutex);
|
||||
list_del_rcu(&mod->bug_list);
|
||||
}
|
||||
|
||||
|
@ -4283,8 +4283,7 @@ sub process {
|
||||
if (defined $realline_next &&
|
||||
exists $lines[$realline_next - 1] &&
|
||||
!defined $suppress_export{$realline_next} &&
|
||||
($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
|
||||
$lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
|
||||
($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/)) {
|
||||
# Handle definitions which produce identifiers with
|
||||
# a prefix:
|
||||
# XXX(foo);
|
||||
@ -4311,8 +4310,7 @@ sub process {
|
||||
}
|
||||
if (!defined $suppress_export{$linenr} &&
|
||||
$prevline =~ /^.\s*$/ &&
|
||||
($line =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
|
||||
$line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
|
||||
($line =~ /EXPORT_SYMBOL.*\((.*)\)/)) {
|
||||
#print "FOO B <$lines[$linenr - 1]>\n";
|
||||
$suppress_export{$linenr} = 2;
|
||||
}
|
||||
|
@ -42,8 +42,9 @@ static int allow_missing_ns_imports;
|
||||
static bool error_occurred;
|
||||
|
||||
enum export {
|
||||
export_plain, export_unused, export_gpl,
|
||||
export_unused_gpl, export_gpl_future, export_unknown
|
||||
export_plain,
|
||||
export_gpl,
|
||||
export_unknown
|
||||
};
|
||||
|
||||
/* In kernel, this size is defined in linux/module.h;
|
||||
@ -292,10 +293,7 @@ static const struct {
|
||||
enum export export;
|
||||
} export_list[] = {
|
||||
{ .str = "EXPORT_SYMBOL", .export = export_plain },
|
||||
{ .str = "EXPORT_UNUSED_SYMBOL", .export = export_unused },
|
||||
{ .str = "EXPORT_SYMBOL_GPL", .export = export_gpl },
|
||||
{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
|
||||
{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
|
||||
{ .str = "(unknown)", .export = export_unknown },
|
||||
};
|
||||
|
||||
@ -354,14 +352,8 @@ static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
|
||||
|
||||
if (strstarts(secname, "___ksymtab+"))
|
||||
return export_plain;
|
||||
else if (strstarts(secname, "___ksymtab_unused+"))
|
||||
return export_unused;
|
||||
else if (strstarts(secname, "___ksymtab_gpl+"))
|
||||
return export_gpl;
|
||||
else if (strstarts(secname, "___ksymtab_unused_gpl+"))
|
||||
return export_unused_gpl;
|
||||
else if (strstarts(secname, "___ksymtab_gpl_future+"))
|
||||
return export_gpl_future;
|
||||
else
|
||||
return export_unknown;
|
||||
}
|
||||
@ -370,14 +362,8 @@ static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
|
||||
{
|
||||
if (sec == elf->export_sec)
|
||||
return export_plain;
|
||||
else if (sec == elf->export_unused_sec)
|
||||
return export_unused;
|
||||
else if (sec == elf->export_gpl_sec)
|
||||
return export_gpl;
|
||||
else if (sec == elf->export_unused_gpl_sec)
|
||||
return export_unused_gpl;
|
||||
else if (sec == elf->export_gpl_future_sec)
|
||||
return export_gpl_future;
|
||||
else
|
||||
return export_unknown;
|
||||
}
|
||||
@ -581,14 +567,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
|
||||
info->modinfo_len = sechdrs[i].sh_size;
|
||||
} else if (strcmp(secname, "__ksymtab") == 0)
|
||||
info->export_sec = i;
|
||||
else if (strcmp(secname, "__ksymtab_unused") == 0)
|
||||
info->export_unused_sec = i;
|
||||
else if (strcmp(secname, "__ksymtab_gpl") == 0)
|
||||
info->export_gpl_sec = i;
|
||||
else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
|
||||
info->export_unused_gpl_sec = i;
|
||||
else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
|
||||
info->export_gpl_future_sec = i;
|
||||
|
||||
if (sechdrs[i].sh_type == SHT_SYMTAB) {
|
||||
unsigned int sh_link_idx;
|
||||
@ -2146,36 +2126,13 @@ static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
|
||||
error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n",
|
||||
m, s);
|
||||
break;
|
||||
case export_unused_gpl:
|
||||
error("GPL-incompatible module %s.ko uses GPL-only symbol marked UNUSED '%s'\n",
|
||||
m, s);
|
||||
break;
|
||||
case export_gpl_future:
|
||||
warn("GPL-incompatible module %s.ko uses future GPL-only symbol '%s'\n",
|
||||
m, s);
|
||||
break;
|
||||
case export_plain:
|
||||
case export_unused:
|
||||
case export_unknown:
|
||||
/* ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_for_unused(enum export exp, const char *m, const char *s)
|
||||
{
|
||||
switch (exp) {
|
||||
case export_unused:
|
||||
case export_unused_gpl:
|
||||
warn("module %s.ko uses symbol '%s' marked UNUSED\n",
|
||||
m, s);
|
||||
break;
|
||||
default:
|
||||
/* ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_exports(struct module *mod)
|
||||
{
|
||||
struct symbol *s, *exp;
|
||||
@ -2206,7 +2163,6 @@ static void check_exports(struct module *mod)
|
||||
|
||||
if (!mod->gpl_compatible)
|
||||
check_for_gpl_usage(exp->export, basename, exp->name);
|
||||
check_for_unused(exp->export, basename, exp->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,10 +140,7 @@ struct elf_info {
|
||||
Elf_Sym *symtab_start;
|
||||
Elf_Sym *symtab_stop;
|
||||
Elf_Section export_sec;
|
||||
Elf_Section export_unused_sec;
|
||||
Elf_Section export_gpl_sec;
|
||||
Elf_Section export_unused_gpl_sec;
|
||||
Elf_Section export_gpl_future_sec;
|
||||
char *strtab;
|
||||
char *modinfo;
|
||||
unsigned int modinfo_len;
|
||||
|
@ -11,14 +11,8 @@ SECTIONS {
|
||||
|
||||
__ksymtab 0 : { *(SORT(___ksymtab+*)) }
|
||||
__ksymtab_gpl 0 : { *(SORT(___ksymtab_gpl+*)) }
|
||||
__ksymtab_unused 0 : { *(SORT(___ksymtab_unused+*)) }
|
||||
__ksymtab_unused_gpl 0 : { *(SORT(___ksymtab_unused_gpl+*)) }
|
||||
__ksymtab_gpl_future 0 : { *(SORT(___ksymtab_gpl_future+*)) }
|
||||
__kcrctab 0 : { *(SORT(___kcrctab+*)) }
|
||||
__kcrctab_gpl 0 : { *(SORT(___kcrctab_gpl+*)) }
|
||||
__kcrctab_unused 0 : { *(SORT(___kcrctab_unused+*)) }
|
||||
__kcrctab_unused_gpl 0 : { *(SORT(___kcrctab_unused_gpl+*)) }
|
||||
__kcrctab_gpl_future 0 : { *(SORT(___kcrctab_gpl_future+*)) }
|
||||
|
||||
.init_array 0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) }
|
||||
|
||||
|
@ -3,8 +3,5 @@
|
||||
|
||||
#define EXPORT_SYMBOL(sym)
|
||||
#define EXPORT_SYMBOL_GPL(sym)
|
||||
#define EXPORT_SYMBOL_GPL_FUTURE(sym)
|
||||
#define EXPORT_UNUSED_SYMBOL(sym)
|
||||
#define EXPORT_UNUSED_SYMBOL_GPL(sym)
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user