diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 274 | 
1 files changed, 161 insertions, 113 deletions
diff --git a/kernel/module.c b/kernel/module.c index f77ac320d0b..f6e08b7cff7 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -68,7 +68,8 @@  /* List of modules, protected by module_mutex or preempt_disable   * (delete uses stop_machine/add uses RCU list operations). */ -static DEFINE_MUTEX(module_mutex); +DEFINE_MUTEX(module_mutex); +EXPORT_SYMBOL_GPL(module_mutex);  static LIST_HEAD(modules);  /* Waiting for a module to finish initializing? */ @@ -76,7 +77,7 @@ static DECLARE_WAIT_QUEUE_HEAD(module_wq);  static BLOCKING_NOTIFIER_HEAD(module_notify_list); -/* Bounds of module allocation, for speeding __module_text_address */ +/* Bounds of module allocation, for speeding __module_address */  static unsigned long module_addr_min = -1UL, module_addr_max = 0;  int register_module_notifier(struct notifier_block * nb) @@ -186,17 +187,6 @@ extern const unsigned long __start___kcrctab_unused_gpl[];  #define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)  #endif -struct symsearch { -	const struct kernel_symbol *start, *stop; -	const unsigned long *crcs; -	enum { -		NOT_GPL_ONLY, -		GPL_ONLY, -		WILL_BE_GPL_ONLY, -	} licence; -	bool unused; -}; -  static bool each_symbol_in_section(const struct symsearch *arr,  				   unsigned int arrsize,  				   struct module *owner, @@ -217,10 +207,8 @@ static bool each_symbol_in_section(const struct symsearch *arr,  }  /* Returns true as soon as fn returns true, otherwise false. */ -static bool each_symbol(bool (*fn)(const struct symsearch *arr, -				   struct module *owner, -				   unsigned int symnum, void *data), -			void *data) +bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner, +			    unsigned int symnum, void *data), void *data)  {  	struct module *mod;  	const struct symsearch arr[] = { @@ -273,6 +261,7 @@ static bool each_symbol(bool (*fn)(const struct symsearch *arr,  	}  	return false;  } +EXPORT_SYMBOL_GPL(each_symbol);  struct find_symbol_arg {  	/* Input */ @@ -283,7 +272,7 @@ struct find_symbol_arg {  	/* Output */  	struct module *owner;  	const unsigned long *crc; -	unsigned long value; +	const struct kernel_symbol *sym;  };  static bool find_symbol_in_section(const struct symsearch *syms, @@ -324,17 +313,17 @@ static bool find_symbol_in_section(const struct symsearch *syms,  	fsa->owner = owner;  	fsa->crc = symversion(syms->crcs, symnum); -	fsa->value = syms->start[symnum].value; +	fsa->sym = &syms->start[symnum];  	return true;  } -/* Find a symbol, return value, (optional) crc and (optional) module - * which owns it */ -static unsigned long find_symbol(const char *name, -				 struct module **owner, -				 const unsigned long **crc, -				 bool gplok, -				 bool warn) +/* Find a symbol and return it, along with, (optional) crc and + * (optional) module which owns it */ +const struct kernel_symbol *find_symbol(const char *name, +					struct module **owner, +					const unsigned long **crc, +					bool gplok, +					bool warn)  {  	struct find_symbol_arg fsa; @@ -347,15 +336,16 @@ static unsigned long find_symbol(const char *name,  			*owner = fsa.owner;  		if (crc)  			*crc = fsa.crc; -		return fsa.value; +		return fsa.sym;  	}  	DEBUGP("Failed to find symbol %s\n", name); -	return -ENOENT; +	return NULL;  } +EXPORT_SYMBOL_GPL(find_symbol);  /* Search for module by name: must hold module_mutex. */ -static struct module *find_module(const char *name) +struct module *find_module(const char *name)  {  	struct module *mod; @@ -365,6 +355,7 @@ static struct module *find_module(const char *name)  	}  	return NULL;  } +EXPORT_SYMBOL_GPL(find_module);  #ifdef CONFIG_SMP @@ -641,7 +632,7 @@ static int already_uses(struct module *a, struct module *b)  }  /* Module a uses b */ -static int use_module(struct module *a, struct module *b) +int use_module(struct module *a, struct module *b)  {  	struct module_use *use;  	int no_warn, err; @@ -674,6 +665,7 @@ static int use_module(struct module *a, struct module *b)  	no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name);  	return 1;  } +EXPORT_SYMBOL_GPL(use_module);  /* Clear the unload stuff of the module. */  static void module_unload_free(struct module *mod) @@ -894,7 +886,7 @@ void __symbol_put(const char *symbol)  	struct module *owner;  	preempt_disable(); -	if (IS_ERR_VALUE(find_symbol(symbol, &owner, NULL, true, false))) +	if (!find_symbol(symbol, &owner, NULL, true, false))  		BUG();  	module_put(owner);  	preempt_enable(); @@ -908,8 +900,10 @@ void symbol_put_addr(void *addr)  	if (core_kernel_text((unsigned long)addr))  		return; -	if (!(modaddr = module_text_address((unsigned long)addr))) -		BUG(); +	/* module_text_address is safe here: we're supposed to have reference +	 * to module from symbol_get, so it can't go away. */ +	modaddr = __module_text_address((unsigned long)addr); +	BUG_ON(!modaddr);  	module_put(modaddr);  }  EXPORT_SYMBOL_GPL(symbol_put_addr); @@ -949,10 +943,11 @@ static inline void module_unload_free(struct module *mod)  {  } -static inline int use_module(struct module *a, struct module *b) +int use_module(struct module *a, struct module *b)  {  	return strong_try_module_get(b) == 0;  } +EXPORT_SYMBOL_GPL(use_module);  static inline void module_unload_init(struct module *mod)  { @@ -995,12 +990,12 @@ static struct module_attribute *modinfo_attrs[] = {  static const char vermagic[] = VERMAGIC_STRING; -static int try_to_force_load(struct module *mod, const char *symname) +static int try_to_force_load(struct module *mod, const char *reason)  {  #ifdef CONFIG_MODULE_FORCE_LOAD  	if (!test_taint(TAINT_FORCED_MODULE)) -		printk("%s: no version for \"%s\" found: kernel tainted.\n", -		       mod->name, symname); +		printk(KERN_WARNING "%s: %s: kernel tainted.\n", +		       mod->name, reason);  	add_taint_module(mod, TAINT_FORCED_MODULE);  	return 0;  #else @@ -1057,9 +1052,9 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,  {  	const unsigned long *crc; -	if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc, true, false))) +	if (!find_symbol("module_layout", NULL, &crc, true, false))  		BUG(); -	return check_version(sechdrs, versindex, "struct_module", mod, crc); +	return check_version(sechdrs, versindex, "module_layout", mod, crc);  }  /* First part is kernel version, which we ignore if module has crcs. */ @@ -1098,25 +1093,25 @@ static inline int same_magic(const char *amagic, const char *bmagic,  /* Resolve a symbol for this module.  I.e. if we find one, record usage.     Must be holding module_mutex. */ -static unsigned long resolve_symbol(Elf_Shdr *sechdrs, -				    unsigned int versindex, -				    const char *name, -				    struct module *mod) +static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, +						  unsigned int versindex, +						  const char *name, +						  struct module *mod)  {  	struct module *owner; -	unsigned long ret; +	const struct kernel_symbol *sym;  	const unsigned long *crc; -	ret = find_symbol(name, &owner, &crc, +	sym = find_symbol(name, &owner, &crc,  			  !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true); -	if (!IS_ERR_VALUE(ret)) { -		/* use_module can fail due to OOM, -		   or module initialization or unloading */ +	/* use_module can fail due to OOM, +	   or module initialization or unloading */ +	if (sym) {  		if (!check_version(sechdrs, versindex, name, mod, crc) ||  		    !use_module(mod, owner)) -			ret = -EINVAL; +			sym = NULL;  	} -	return ret; +	return sym;  }  /* @@ -1491,6 +1486,9 @@ static void free_module(struct module *mod)  	/* Module unload stuff */  	module_unload_free(mod); +	/* Free any allocated parameters. */ +	destroy_params(mod->kp, mod->num_kp); +  	/* release any pointers to mcount in this module */  	ftrace_release(mod->module_core, mod->core_size); @@ -1513,17 +1511,15 @@ static void free_module(struct module *mod)  void *__symbol_get(const char *symbol)  {  	struct module *owner; -	unsigned long value; +	const struct kernel_symbol *sym;  	preempt_disable(); -	value = find_symbol(symbol, &owner, NULL, true, true); -	if (IS_ERR_VALUE(value)) -		value = 0; -	else if (strong_try_module_get(owner)) -		value = 0; +	sym = find_symbol(symbol, &owner, NULL, true, true); +	if (sym && strong_try_module_get(owner)) +		sym = NULL;  	preempt_enable(); -	return (void *)value; +	return sym ? (void *)sym->value : NULL;  }  EXPORT_SYMBOL_GPL(__symbol_get); @@ -1551,8 +1547,7 @@ static int verify_export_symbols(struct module *mod)  	for (i = 0; i < ARRAY_SIZE(arr); i++) {  		for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { -			if (!IS_ERR_VALUE(find_symbol(s->name, &owner, -						      NULL, true, false))) { +			if (find_symbol(s->name, &owner, NULL, true, false)) {  				printk(KERN_ERR  				       "%s: exports duplicate symbol %s"  				       " (owned by %s)\n", @@ -1576,6 +1571,7 @@ static int simplify_symbols(Elf_Shdr *sechdrs,  	unsigned long secbase;  	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);  	int ret = 0; +	const struct kernel_symbol *ksym;  	for (i = 1; i < n; i++) {  		switch (sym[i].st_shndx) { @@ -1595,13 +1591,14 @@ static int simplify_symbols(Elf_Shdr *sechdrs,  			break;  		case SHN_UNDEF: -			sym[i].st_value -			  = resolve_symbol(sechdrs, versindex, -					   strtab + sym[i].st_name, mod); - +			ksym = resolve_symbol(sechdrs, versindex, +					      strtab + sym[i].st_name, mod);  			/* Ok if resolved.  */ -			if (!IS_ERR_VALUE(sym[i].st_value)) +			if (ksym) { +				sym[i].st_value = ksym->value;  				break; +			} +  			/* Ok if weak.  */  			if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK)  				break; @@ -1676,8 +1673,7 @@ static void layout_sections(struct module *mod,  			if ((s->sh_flags & masks[m][0]) != masks[m][0]  			    || (s->sh_flags & masks[m][1])  			    || s->sh_entsize != ~0UL -			    || strncmp(secstrings + s->sh_name, -				       ".init", 5) == 0) +			    || strstarts(secstrings + s->sh_name, ".init"))  				continue;  			s->sh_entsize = get_offset(mod, &mod->core_size, s, i);  			DEBUGP("\t%s\n", secstrings + s->sh_name); @@ -1694,8 +1690,7 @@ static void layout_sections(struct module *mod,  			if ((s->sh_flags & masks[m][0]) != masks[m][0]  			    || (s->sh_flags & masks[m][1])  			    || s->sh_entsize != ~0UL -			    || strncmp(secstrings + s->sh_name, -				       ".init", 5) != 0) +			    || !strstarts(secstrings + s->sh_name, ".init"))  				continue;  			s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)  					 | INIT_OFFSET_MASK); @@ -1828,8 +1823,7 @@ static char elf_type(const Elf_Sym *sym,  		else  			return 'b';  	} -	if (strncmp(secstrings + sechdrs[sym->st_shndx].sh_name, -		    ".debug", strlen(".debug")) == 0) +	if (strstarts(secstrings + sechdrs[sym->st_shndx].sh_name, ".debug"))  		return 'n';  	return '?';  } @@ -1898,8 +1892,7 @@ static noinline struct module *load_module(void __user *umod,  	unsigned int symindex = 0;  	unsigned int strindex = 0;  	unsigned int modindex, versindex, infoindex, pcpuindex; -	unsigned int num_kp, num_mcount; -	struct kernel_param *kp; +	unsigned int num_mcount;  	struct module *mod;  	long err = 0;  	void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ @@ -1916,12 +1909,6 @@ static noinline struct module *load_module(void __user *umod,  	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; @@ -1962,9 +1949,12 @@ static noinline struct module *load_module(void __user *umod,  		}  #ifndef CONFIG_MODULE_UNLOAD  		/* Don't load .exit sections */ -		if (strncmp(secstrings+sechdrs[i].sh_name, ".exit", 5) == 0) +		if (strstarts(secstrings+sechdrs[i].sh_name, ".exit"))  			sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;  #endif +		/* Don't keep __versions around; it's just for loading. */ +		if (strcmp(secstrings + sechdrs[i].sh_name, "__versions") == 0) +			sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;  	}  	modindex = find_sec(hdr, sechdrs, secstrings, @@ -2006,7 +1996,7 @@ static noinline struct module *load_module(void __user *umod,  	modmagic = get_modinfo(sechdrs, infoindex, "vermagic");  	/* This is allowed: modprobe --force will invalidate it. */  	if (!modmagic) { -		err = try_to_force_load(mod, "magic"); +		err = try_to_force_load(mod, "bad vermagic");  		if (err)  			goto free_hdr;  	} else if (!same_magic(modmagic, vermagic, versindex)) { @@ -2144,8 +2134,8 @@ static noinline struct module *load_module(void __user *umod,  	/* Now we've got everything in the final locations, we can  	 * find optional sections. */ -	kp = section_objs(hdr, sechdrs, secstrings, "__param", sizeof(*kp), -			  &num_kp); +	mod->kp = section_objs(hdr, sechdrs, secstrings, "__param", +			       sizeof(*mod->kp), &mod->num_kp);  	mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab",  				 sizeof(*mod->syms), &mod->num_syms);  	mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab"); @@ -2195,8 +2185,8 @@ static noinline struct module *load_module(void __user *umod,  	    || (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs)  #endif  		) { -		printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name); -		err = try_to_force_load(mod, "nocrc"); +		err = try_to_force_load(mod, +					"no versions for exported symbols");  		if (err)  			goto cleanup;  	} @@ -2291,11 +2281,11 @@ static noinline struct module *load_module(void __user *umod,  	 */  	list_add_rcu(&mod->list, &modules); -	err = parse_args(mod->name, mod->args, kp, num_kp, NULL); +	err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL);  	if (err < 0)  		goto unlink; -	err = mod_sysfs_setup(mod, kp, num_kp); +	err = mod_sysfs_setup(mod, mod->kp, mod->num_kp);  	if (err < 0)  		goto unlink;  	add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); @@ -2304,12 +2294,13 @@ static noinline struct module *load_module(void __user *umod,  	/* Get rid of temporary copy */  	vfree(hdr); -	stop_machine_destroy();  	/* Done! */  	return mod;   unlink: -	stop_machine(__unlink_module, mod, NULL); +	/* Unlink carefully: kallsyms could be walking list. */ +	list_del_rcu(&mod->list); +	synchronize_sched();  	module_arch_cleanup(mod);   cleanup:  	kobject_del(&mod->mkobj.kobj); @@ -2317,8 +2308,8 @@ static noinline struct module *load_module(void __user *umod,  	ftrace_release(mod->module_core, mod->core_size);   free_unload:  	module_unload_free(mod); - free_init:  #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) + free_init:  	percpu_modfree(mod->refptr);  #endif  	module_free(mod, mod->module_init); @@ -2332,7 +2323,6 @@ static noinline struct module *load_module(void __user *umod,  	kfree(args);   free_hdr:  	vfree(hdr); -	stop_machine_destroy();  	return ERR_PTR(err);   truncated: @@ -2609,6 +2599,25 @@ unsigned long module_kallsyms_lookup_name(const char *name)  	preempt_enable();  	return ret;  } + +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; + +	list_for_each_entry(mod, &modules, list) { +		for (i = 0; i < mod->num_symtab; i++) { +			ret = fn(data, mod->strtab + mod->symtab[i].st_name, +				 mod, mod->symtab[i].st_value); +			if (ret != 0) +				return ret; +		} +	} +	return 0; +}  #endif /* CONFIG_KALLSYMS */  static char *module_flags(struct module *mod, char *buf) @@ -2744,29 +2753,31 @@ const struct exception_table_entry *search_module_extables(unsigned long addr)  }  /* - * Is this a valid module address? + * is_module_address - is this address inside a module? + * @addr: the address to check. + * + * See is_module_text_address() if you simply want to see if the address + * is code (not data).   */ -int is_module_address(unsigned long addr) +bool is_module_address(unsigned long addr)  { -	struct module *mod; +	bool ret;  	preempt_disable(); - -	list_for_each_entry_rcu(mod, &modules, list) { -		if (within_module_core(addr, mod)) { -			preempt_enable(); -			return 1; -		} -	} - +	ret = __module_address(addr) != NULL;  	preempt_enable(); -	return 0; +	return ret;  } - -/* Is this a valid kernel address? */ -__notrace_funcgraph struct module *__module_text_address(unsigned long addr) +/* + * __module_address - get the module which contains an address. + * @addr: the address. + * + * Must be called with preempt disabled or module mutex held so that + * module doesn't get freed during this. + */ +__notrace_funcgraph struct module *__module_address(unsigned long addr)  {  	struct module *mod; @@ -2774,22 +2785,51 @@ __notrace_funcgraph struct module *__module_text_address(unsigned long addr)  		return NULL;  	list_for_each_entry_rcu(mod, &modules, list) -		if (within(addr, mod->module_init, mod->init_text_size) -		    || within(addr, mod->module_core, mod->core_text_size)) +		if (within_module_core(addr, mod) +		    || within_module_init(addr, mod))  			return mod;  	return NULL;  } +EXPORT_SYMBOL_GPL(__module_address); -struct module *module_text_address(unsigned long addr) +/* + * is_module_text_address - is this address inside module code? + * @addr: the address to check. + * + * See is_module_address() if you simply want to see if the address is + * anywhere in a module.  See kernel_text_address() for testing if an + * address corresponds to kernel or module code. + */ +bool is_module_text_address(unsigned long addr)  { -	struct module *mod; +	bool ret;  	preempt_disable(); -	mod = __module_text_address(addr); +	ret = __module_text_address(addr) != NULL;  	preempt_enable(); +	return ret; +} + +/* + * __module_text_address - get the module whose code contains an address. + * @addr: the address. + * + * Must be called with preempt disabled or module mutex held so that + * module doesn't get freed during this. + */ +struct module *__module_text_address(unsigned long addr) +{ +	struct module *mod = __module_address(addr); +	if (mod) { +		/* Make sure it's within the text section. */ +		if (!within(addr, mod->module_init, mod->init_text_size) +		    && !within(addr, mod->module_core, mod->core_text_size)) +			mod = NULL; +	}  	return mod;  } +EXPORT_SYMBOL_GPL(__module_text_address);  /* Don't grab lock, we're oopsing. */  void print_modules(void) @@ -2809,9 +2849,17 @@ void print_modules(void)  }  #ifdef CONFIG_MODVERSIONS -/* Generate the signature for struct module here, too, for modversions. */ -void struct_module(struct module *mod) { return; } -EXPORT_SYMBOL(struct_module); +/* Generate the signature for all relevant module structures here. + * If these change, we don't want to try to parse the module. */ +void module_layout(struct module *mod, +		   struct modversion_info *ver, +		   struct kernel_param *kp, +		   struct kernel_symbol *ks, +		   struct marker *marker, +		   struct tracepoint *tp) +{ +} +EXPORT_SYMBOL(module_layout);  #endif  #ifdef CONFIG_MARKERS  |