diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 59 | 
1 files changed, 44 insertions, 15 deletions
diff --git a/kernel/module.c b/kernel/module.c index dd2a54155b5..f47cce910f2 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -757,8 +757,16 @@ sys_delete_module(const char __user *name_user, unsigned int flags)  		return -EFAULT;  	name[MODULE_NAME_LEN-1] = '\0'; -	if (mutex_lock_interruptible(&module_mutex) != 0) -		return -EINTR; +	/* Create stop_machine threads since free_module relies on +	 * a non-failing stop_machine call. */ +	ret = stop_machine_create(); +	if (ret) +		return ret; + +	if (mutex_lock_interruptible(&module_mutex) != 0) { +		ret = -EINTR; +		goto out_stop; +	}  	mod = find_module(name);  	if (!mod) { @@ -817,10 +825,12 @@ sys_delete_module(const char __user *name_user, unsigned int flags)   out:  	mutex_unlock(&module_mutex); +out_stop: +	stop_machine_destroy();  	return ret;  } -static void print_unload_info(struct seq_file *m, struct module *mod) +static inline void print_unload_info(struct seq_file *m, struct module *mod)  {  	struct module_use *use;  	int printed_something = 0; @@ -893,7 +903,7 @@ void module_put(struct module *module)  EXPORT_SYMBOL(module_put);  #else /* !CONFIG_MODULE_UNLOAD */ -static void print_unload_info(struct seq_file *m, struct module *mod) +static inline void print_unload_info(struct seq_file *m, struct module *mod)  {  	/* We don't know the usage count, or what modules are using. */  	seq_printf(m, " - -"); @@ -1578,11 +1588,21 @@ static int simplify_symbols(Elf_Shdr *sechdrs,  	return ret;  } +/* Additional bytes needed by arch in front of individual sections */ +unsigned int __weak arch_mod_section_prepend(struct module *mod, +					     unsigned int section) +{ +	/* default implementation just returns zero */ +	return 0; +} +  /* Update size with this section: return offset. */ -static long get_offset(unsigned int *size, Elf_Shdr *sechdr) +static long get_offset(struct module *mod, unsigned int *size, +		       Elf_Shdr *sechdr, unsigned int section)  {  	long ret; +	*size += arch_mod_section_prepend(mod, section);  	ret = ALIGN(*size, sechdr->sh_addralign ?: 1);  	*size = ret + sechdr->sh_size;  	return ret; @@ -1622,7 +1642,7 @@ static void layout_sections(struct module *mod,  			    || strncmp(secstrings + s->sh_name,  				       ".init", 5) == 0)  				continue; -			s->sh_entsize = get_offset(&mod->core_size, s); +			s->sh_entsize = get_offset(mod, &mod->core_size, s, i);  			DEBUGP("\t%s\n", secstrings + s->sh_name);  		}  		if (m == 0) @@ -1640,7 +1660,7 @@ static void layout_sections(struct module *mod,  			    || strncmp(secstrings + s->sh_name,  				       ".init", 5) != 0)  				continue; -			s->sh_entsize = (get_offset(&mod->init_size, s) +			s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)  					 | INIT_OFFSET_MASK);  			DEBUGP("\t%s\n", secstrings + s->sh_name);  		} @@ -1725,15 +1745,15 @@ static const struct kernel_symbol *lookup_symbol(const char *name,  	return NULL;  } -static int is_exported(const char *name, const struct module *mod) +static int is_exported(const char *name, unsigned long value, +		       const struct module *mod)  { -	if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab)) -		return 1; +	const struct kernel_symbol *ks; +	if (!mod) +		ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);  	else -		if (mod && lookup_symbol(name, mod->syms, mod->syms + mod->num_syms)) -			return 1; -		else -			return 0; +		ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms); +	return ks != NULL && ks->value == value;  }  /* As per nm */ @@ -1865,6 +1885,13 @@ static noinline struct module *load_module(void __user *umod,  	/* vmalloc barfs on "unusual" numbers.  Check here */  	if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)  		return ERR_PTR(-ENOMEM); + +	/* Create stop_machine threads since the error path relies on +	 * a non-failing stop_machine call. */ +	err = stop_machine_create(); +	if (err) +		goto free_hdr; +  	if (copy_from_user(hdr, umod, len) != 0) {  		err = -EFAULT;  		goto free_hdr; @@ -2248,6 +2275,7 @@ static noinline struct module *load_module(void __user *umod,  	/* Get rid of temporary copy */  	vfree(hdr); +	stop_machine_destroy();  	/* Done! */  	return mod; @@ -2270,6 +2298,7 @@ static noinline struct module *load_module(void __user *umod,  	kfree(args);   free_hdr:  	vfree(hdr); +	stop_machine_destroy();  	return ERR_PTR(err);   truncated: @@ -2504,7 +2533,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,  			strlcpy(name, mod->strtab + mod->symtab[symnum].st_name,  				KSYM_NAME_LEN);  			strlcpy(module_name, mod->name, MODULE_NAME_LEN); -			*exported = is_exported(name, mod); +			*exported = is_exported(name, *value, mod);  			preempt_enable();  			return 0;  		}  | 
