diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 124 | 
1 files changed, 69 insertions, 55 deletions
diff --git a/kernel/module.c b/kernel/module.c index 0e54d5bf0097..3d8f126208e3 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -46,7 +46,7 @@  #include <linux/string.h>  #include <linux/mutex.h>  #include <linux/rculist.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h>  #include <asm/cacheflush.h>  #include <asm/mmu_context.h>  #include <linux/license.h> @@ -313,8 +313,11 @@ struct load_info {  	} index;  }; -/* We require a truly strong try_module_get(): 0 means failure due to -   ongoing or failed initialization etc. */ +/* + * We require a truly strong try_module_get(): 0 means success. + * Otherwise an error is returned due to ongoing or failed + * initialization etc. + */  static inline int strong_try_module_get(struct module *mod)  {  	BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED); @@ -330,7 +333,7 @@ static inline void add_taint_module(struct module *mod, unsigned flag,  				    enum lockdep_ok lockdep_ok)  {  	add_taint(flag, lockdep_ok); -	mod->taints |= (1U << flag); +	set_bit(flag, &mod->taints);  }  /* @@ -386,16 +389,16 @@ 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 unsigned long __start___kcrctab[]; -extern const unsigned long __start___kcrctab_gpl[]; -extern const unsigned long __start___kcrctab_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 unsigned long __start___kcrctab_unused[]; -extern const unsigned long __start___kcrctab_unused_gpl[]; +extern const s32 __start___kcrctab_unused[]; +extern const s32 __start___kcrctab_unused_gpl[];  #endif  #ifndef CONFIG_MODVERSIONS @@ -494,7 +497,7 @@ struct find_symbol_arg {  	/* Output */  	struct module *owner; -	const unsigned long *crc; +	const s32 *crc;  	const struct kernel_symbol *sym;  }; @@ -560,7 +563,7 @@ static bool find_symbol_in_section(const struct symsearch *syms,   * (optional) module which owns it.  Needs preempt disabled or module_mutex. */  const struct kernel_symbol *find_symbol(const char *name,  					struct module **owner, -					const unsigned long **crc, +					const s32 **crc,  					bool gplok,  					bool warn)  { @@ -1138,24 +1141,13 @@ static inline int module_unload_init(struct module *mod)  static size_t module_flags_taint(struct module *mod, char *buf)  {  	size_t l = 0; +	int i; + +	for (i = 0; i < TAINT_FLAGS_COUNT; i++) { +		if (taint_flags[i].module && test_bit(i, &mod->taints)) +			buf[l++] = taint_flags[i].c_true; +	} -	if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE)) -		buf[l++] = 'P'; -	if (mod->taints & (1 << TAINT_OOT_MODULE)) -		buf[l++] = 'O'; -	if (mod->taints & (1 << TAINT_FORCED_MODULE)) -		buf[l++] = 'F'; -	if (mod->taints & (1 << TAINT_CRAP)) -		buf[l++] = 'C'; -	if (mod->taints & (1 << TAINT_UNSIGNED_MODULE)) -		buf[l++] = 'E'; -	if (mod->taints & (1 << TAINT_LIVEPATCH)) -		buf[l++] = 'K'; -	/* -	 * TAINT_FORCED_RMMOD: could be added. -	 * TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't -	 * apply to modules. -	 */  	return l;  } @@ -1257,23 +1249,17 @@ static int try_to_force_load(struct module *mod, const char *reason)  }  #ifdef CONFIG_MODVERSIONS -/* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */ -static unsigned long maybe_relocated(unsigned long crc, -				     const struct module *crc_owner) + +static u32 resolve_rel_crc(const s32 *crc)  { -#ifdef ARCH_RELOCATES_KCRCTAB -	if (crc_owner == NULL) -		return crc - (unsigned long)reloc_start; -#endif -	return crc; +	return *(u32 *)((void *)crc + *crc);  }  static int check_version(Elf_Shdr *sechdrs,  			 unsigned int versindex,  			 const char *symname,  			 struct module *mod, -			 const unsigned long *crc, -			 const struct module *crc_owner) +			 const s32 *crc)  {  	unsigned int i, num_versions;  	struct modversion_info *versions; @@ -1291,13 +1277,19 @@ static int check_version(Elf_Shdr *sechdrs,  		/ sizeof(struct modversion_info);  	for (i = 0; i < num_versions; i++) { +		u32 crcval; +  		if (strcmp(versions[i].name, symname) != 0)  			continue; -		if (versions[i].crc == maybe_relocated(*crc, crc_owner)) +		if (IS_ENABLED(CONFIG_MODULE_REL_CRCS)) +			crcval = resolve_rel_crc(crc); +		else +			crcval = *crc; +		if (versions[i].crc == crcval)  			return 1; -		pr_debug("Found checksum %lX vs module %lX\n", -		       maybe_relocated(*crc, crc_owner), versions[i].crc); +		pr_debug("Found checksum %X vs module %lX\n", +			 crcval, versions[i].crc);  		goto bad_version;  	} @@ -1315,7 +1307,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,  					  unsigned int versindex,  					  struct module *mod)  { -	const unsigned long *crc; +	const s32 *crc;  	/*  	 * Since this should be found in kernel (which can't be removed), no @@ -1329,8 +1321,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,  	}  	preempt_enable();  	return check_version(sechdrs, versindex, -			     VMLINUX_SYMBOL_STR(module_layout), mod, crc, -			     NULL); +			     VMLINUX_SYMBOL_STR(module_layout), mod, crc);  }  /* First part is kernel version, which we ignore if module has crcs. */ @@ -1348,8 +1339,7 @@ static inline int check_version(Elf_Shdr *sechdrs,  				unsigned int versindex,  				const char *symname,  				struct module *mod, -				const unsigned long *crc, -				const struct module *crc_owner) +				const s32 *crc)  {  	return 1;  } @@ -1376,7 +1366,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,  {  	struct module *owner;  	const struct kernel_symbol *sym; -	const unsigned long *crc; +	const s32 *crc;  	int err;  	/* @@ -1391,8 +1381,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,  	if (!sym)  		goto unlock; -	if (!check_version(info->sechdrs, info->index.vers, name, mod, crc, -			   owner)) { +	if (!check_version(info->sechdrs, info->index.vers, name, mod, crc)) {  		sym = ERR_PTR(-EINVAL);  		goto getname;  	} @@ -1911,6 +1900,9 @@ static void frob_writable_data(const struct module_layout *layout,  /* livepatching wants to disable read-only so it can frob module. */  void module_disable_ro(const struct module *mod)  { +	if (!rodata_enabled) +		return; +  	frob_text(&mod->core_layout, set_memory_rw);  	frob_rodata(&mod->core_layout, set_memory_rw);  	frob_ro_after_init(&mod->core_layout, set_memory_rw); @@ -1920,6 +1912,9 @@ void module_disable_ro(const struct module *mod)  void module_enable_ro(const struct module *mod, bool after_init)  { +	if (!rodata_enabled) +		return; +  	frob_text(&mod->core_layout, set_memory_ro);  	frob_rodata(&mod->core_layout, set_memory_ro);  	frob_text(&mod->init_layout, set_memory_ro); @@ -1952,6 +1947,9 @@ void set_all_modules_text_rw(void)  {  	struct module *mod; +	if (!rodata_enabled) +		return; +  	mutex_lock(&module_mutex);  	list_for_each_entry_rcu(mod, &modules, list) {  		if (mod->state == MODULE_STATE_UNFORMED) @@ -1968,9 +1966,18 @@ void set_all_modules_text_ro(void)  {  	struct module *mod; +	if (!rodata_enabled) +		return; +  	mutex_lock(&module_mutex);  	list_for_each_entry_rcu(mod, &modules, list) { -		if (mod->state == MODULE_STATE_UNFORMED) +		/* +		 * Ignore going modules since it's possible that ro +		 * protection has already been disabled, otherwise we'll +		 * run into protection faults at module deallocation. +		 */ +		if (mod->state == MODULE_STATE_UNFORMED || +			mod->state == MODULE_STATE_GOING)  			continue;  		frob_text(&mod->core_layout, set_memory_ro); @@ -1981,10 +1988,12 @@ void set_all_modules_text_ro(void)  static void disable_ro_nx(const struct module_layout *layout)  { -	frob_text(layout, set_memory_rw); -	frob_rodata(layout, set_memory_rw); +	if (rodata_enabled) { +		frob_text(layout, set_memory_rw); +		frob_rodata(layout, set_memory_rw); +		frob_ro_after_init(layout, set_memory_rw); +	}  	frob_rodata(layout, set_memory_x); -	frob_ro_after_init(layout, set_memory_rw);  	frob_ro_after_init(layout, set_memory_x);  	frob_writable_data(layout, set_memory_x);  } @@ -3709,6 +3718,7 @@ static int load_module(struct load_info *info, const char __user *uargs,   sysfs_cleanup:  	mod_sysfs_teardown(mod);   coming_cleanup: +	mod->state = MODULE_STATE_GOING;  	blocking_notifier_call_chain(&module_notify_list,  				     MODULE_STATE_GOING, mod);  	klp_module_going(mod); @@ -4042,6 +4052,10 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,  }  #endif /* CONFIG_KALLSYMS */ +/* Maximum number of characters written by module_flags() */ +#define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4) + +/* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */  static char *module_flags(struct module *mod, char *buf)  {  	int bx = 0; @@ -4086,7 +4100,7 @@ static void m_stop(struct seq_file *m, void *p)  static int m_show(struct seq_file *m, void *p)  {  	struct module *mod = list_entry(p, struct module, list); -	char buf[8]; +	char buf[MODULE_FLAGS_BUF_SIZE];  	/* We always ignore unformed modules. */  	if (mod->state == MODULE_STATE_UNFORMED) @@ -4257,7 +4271,7 @@ EXPORT_SYMBOL_GPL(__module_text_address);  void print_modules(void)  {  	struct module *mod; -	char buf[8]; +	char buf[MODULE_FLAGS_BUF_SIZE];  	printk(KERN_DEFAULT "Modules linked in:");  	/* Most callers should already have preempt disabled, but make sure */  |