diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 71 | 
1 files changed, 44 insertions, 27 deletions
| diff --git a/kernel/module.c b/kernel/module.c index 0e54d5bf0097..5088784c0cf9 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);  }  /* @@ -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].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;  } @@ -1911,6 +1903,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 +1915,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 +1950,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 +1969,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 +1991,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 +3721,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 +4055,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 +4103,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 +4274,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 */ |