Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c9871de authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus:
  module: don't call percpu_modfree on NULL pointer.
  module: fix memory leak when load fails after srcversion/version allocated
  module: preferred way to use MODULE_AUTHOR
  param: allow whitespace as kernel parameter separator
  module: reduce string table for loaded modules (v2)
  module: reduce symbol table for loaded modules (v2)
parents dc2af6a6 ffa9f12a
Loading
Loading
Loading
Loading
+12 −5
Original line number Diff line number Diff line
@@ -128,7 +128,10 @@ extern struct module __this_module;
 */
#define MODULE_LICENSE(_license) MODULE_INFO(license, _license)

/* Author, ideally of form NAME[, NAME]*[ and NAME] */
/*
 * Author(s), use "Name <email>" or just "Name", for multiple
 * authors use multiple MODULE_AUTHOR() statements/lines.
 */
#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
  
/* What your module does. */
@@ -308,10 +311,14 @@ struct module
#endif

#ifdef CONFIG_KALLSYMS
	/* We keep the symbol and string tables for kallsyms. */
	Elf_Sym *symtab;
	unsigned int num_symtab;
	char *strtab;
	/*
	 * We keep the symbol and string tables for kallsyms.
	 * The core_* fields below are temporary, loader-only (they
	 * could really be discarded after module init).
	 */
	Elf_Sym *symtab, *core_symtab;
	unsigned int num_symtab, core_num_syms;
	char *strtab, *core_strtab;

	/* Section attributes */
	struct module_sect_attrs *sect_attrs;
+149 −10
Original line number Diff line number Diff line
@@ -1797,6 +1797,17 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
	}
}

static void free_modinfo(struct module *mod)
{
	struct module_attribute *attr;
	int i;

	for (i = 0; (attr = modinfo_attrs[i]); i++) {
		if (attr->free)
			attr->free(mod);
	}
}

#ifdef CONFIG_KALLSYMS

/* lookup symbol in given range of kernel_symbols */
@@ -1862,13 +1873,93 @@ static char elf_type(const Elf_Sym *sym,
	return '?';
}

static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
                           unsigned int shnum)
{
	const Elf_Shdr *sec;

	if (src->st_shndx == SHN_UNDEF
	    || src->st_shndx >= shnum
	    || !src->st_name)
		return false;

	sec = sechdrs + src->st_shndx;
	if (!(sec->sh_flags & SHF_ALLOC)
#ifndef CONFIG_KALLSYMS_ALL
	    || !(sec->sh_flags & SHF_EXECINSTR)
#endif
	    || (sec->sh_entsize & INIT_OFFSET_MASK))
		return false;

	return true;
}

static unsigned long layout_symtab(struct module *mod,
				   Elf_Shdr *sechdrs,
				   unsigned int symindex,
				   unsigned int strindex,
				   const Elf_Ehdr *hdr,
				   const char *secstrings,
				   unsigned long *pstroffs,
				   unsigned long *strmap)
{
	unsigned long symoffs;
	Elf_Shdr *symsect = sechdrs + symindex;
	Elf_Shdr *strsect = sechdrs + strindex;
	const Elf_Sym *src;
	const char *strtab;
	unsigned int i, nsrc, ndst;

	/* Put symbol section at end of init part of module. */
	symsect->sh_flags |= SHF_ALLOC;
	symsect->sh_entsize = get_offset(mod, &mod->init_size, symsect,
					 symindex) | INIT_OFFSET_MASK;
	DEBUGP("\t%s\n", secstrings + symsect->sh_name);

	src = (void *)hdr + symsect->sh_offset;
	nsrc = symsect->sh_size / sizeof(*src);
	strtab = (void *)hdr + strsect->sh_offset;
	for (ndst = i = 1; i < nsrc; ++i, ++src)
		if (is_core_symbol(src, sechdrs, hdr->e_shnum)) {
			unsigned int j = src->st_name;

			while(!__test_and_set_bit(j, strmap) && strtab[j])
				++j;
			++ndst;
		}

	/* Append room for core symbols at end of core part. */
	symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
	mod->core_size = symoffs + ndst * sizeof(Elf_Sym);

	/* Put string table section at end of init part of module. */
	strsect->sh_flags |= SHF_ALLOC;
	strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
					 strindex) | INIT_OFFSET_MASK;
	DEBUGP("\t%s\n", secstrings + strsect->sh_name);

	/* Append room for core symbols' strings at end of core part. */
	*pstroffs = mod->core_size;
	__set_bit(0, strmap);
	mod->core_size += bitmap_weight(strmap, strsect->sh_size);

	return symoffs;
}

static void add_kallsyms(struct module *mod,
			 Elf_Shdr *sechdrs,
			 unsigned int shnum,
			 unsigned int symindex,
			 unsigned int strindex,
			 const char *secstrings)
			 unsigned long symoffs,
			 unsigned long stroffs,
			 const char *secstrings,
			 unsigned long *strmap)
{
	unsigned int i;
	unsigned int i, ndst;
	const Elf_Sym *src;
	Elf_Sym *dst;
	char *s;

	mod->symtab = (void *)sechdrs[symindex].sh_addr;
	mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
@@ -1878,13 +1969,44 @@ static void add_kallsyms(struct module *mod,
	for (i = 0; i < mod->num_symtab; i++)
		mod->symtab[i].st_info
			= elf_type(&mod->symtab[i], sechdrs, secstrings, mod);

	mod->core_symtab = dst = mod->module_core + symoffs;
	src = mod->symtab;
	*dst = *src;
	for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) {
		if (!is_core_symbol(src, sechdrs, shnum))
			continue;
		dst[ndst] = *src;
		dst[ndst].st_name = bitmap_weight(strmap, dst[ndst].st_name);
		++ndst;
	}
	mod->core_num_syms = ndst;

	mod->core_strtab = s = mod->module_core + stroffs;
	for (*s = 0, i = 1; i < sechdrs[strindex].sh_size; ++i)
		if (test_bit(i, strmap))
			*++s = mod->strtab[i];
}
#else
static inline unsigned long layout_symtab(struct module *mod,
					  Elf_Shdr *sechdrs,
					  unsigned int symindex,
					  unsigned int strindex,
					  const Elf_Hdr *hdr,
					  const char *secstrings,
					  unsigned long *pstroffs,
					  unsigned long *strmap)
{
}
static inline void add_kallsyms(struct module *mod,
				Elf_Shdr *sechdrs,
				unsigned int shnum,
				unsigned int symindex,
				unsigned int strindex,
				const char *secstrings)
				unsigned long symoffs,
				unsigned long stroffs,
				const char *secstrings,
				const unsigned long *strmap)
{
}
#endif /* CONFIG_KALLSYMS */
@@ -1959,6 +2081,9 @@ static noinline struct module *load_module(void __user *umod,
	struct module *mod;
	long err = 0;
	void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
#ifdef CONFIG_KALLSYMS
	unsigned long symoffs, stroffs, *strmap;
#endif
	mm_segment_t old_fs;

	DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
@@ -2040,11 +2165,6 @@ static noinline struct module *load_module(void __user *umod,
	/* Don't keep modinfo and version sections. */
	sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
	sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
#ifdef CONFIG_KALLSYMS
	/* Keep symbol and string tables for decoding later. */
	sechdrs[symindex].sh_flags |= SHF_ALLOC;
	sechdrs[strindex].sh_flags |= SHF_ALLOC;
#endif

	/* Check module struct version now, before we try to use module. */
	if (!check_modstruct_version(sechdrs, versindex, mod)) {
@@ -2080,6 +2200,13 @@ static noinline struct module *load_module(void __user *umod,
		goto free_hdr;
	}

	strmap = kzalloc(BITS_TO_LONGS(sechdrs[strindex].sh_size)
			 * sizeof(long), GFP_KERNEL);
	if (!strmap) {
		err = -ENOMEM;
		goto free_mod;
	}

	if (find_module(mod->name)) {
		err = -EEXIST;
		goto free_mod;
@@ -2109,6 +2236,8 @@ static noinline struct module *load_module(void __user *umod,
	   this is done generically; there doesn't appear to be any
	   special cases for the architectures. */
	layout_sections(mod, hdr, sechdrs, secstrings);
	symoffs = layout_symtab(mod, sechdrs, symindex, strindex, hdr,
				secstrings, &stroffs, strmap);

	/* Do the allocs. */
	ptr = module_alloc_update_bounds(mod->core_size);
@@ -2313,7 +2442,10 @@ static noinline struct module *load_module(void __user *umod,
	percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr,
		       sechdrs[pcpuindex].sh_size);

	add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
	add_kallsyms(mod, sechdrs, hdr->e_shnum, symindex, strindex,
		     symoffs, stroffs, secstrings, strmap);
	kfree(strmap);
	strmap = NULL;

	if (!mod->taints) {
		struct _ddebug *debug;
@@ -2385,13 +2517,14 @@ static noinline struct module *load_module(void __user *umod,
	synchronize_sched();
	module_arch_cleanup(mod);
 cleanup:
	free_modinfo(mod);
	kobject_del(&mod->mkobj.kobj);
	kobject_put(&mod->mkobj.kobj);
 free_unload:
	module_unload_free(mod);
#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
 free_init:
	percpu_modfree(mod->refptr);
 free_init:
#endif
	module_free(mod, mod->module_init);
 free_core:
@@ -2402,6 +2535,7 @@ static noinline struct module *load_module(void __user *umod,
		percpu_modfree(percpu);
 free_mod:
	kfree(args);
	kfree(strmap);
 free_hdr:
	vfree(hdr);
	return ERR_PTR(err);
@@ -2491,6 +2625,11 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
	/* Drop initial reference. */
	module_put(mod);
	trim_init_extable(mod);
#ifdef CONFIG_KALLSYMS
	mod->num_symtab = mod->core_num_syms;
	mod->symtab = mod->core_symtab;
	mod->strtab = mod->core_strtab;
#endif
	module_free(mod, mod->module_init);
	mod->module_init = NULL;
	mod->init_size = 0;
+4 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/ctype.h>

#if 0
#define DEBUGP printk
@@ -87,7 +88,7 @@ static char *next_arg(char *args, char **param, char **val)
	}

	for (i = 0; args[i]; i++) {
		if (args[i] == ' ' && !in_quote)
		if (isspace(args[i]) && !in_quote)
			break;
		if (equals == 0) {
			if (args[i] == '=')
@@ -121,7 +122,7 @@ static char *next_arg(char *args, char **param, char **val)
		next = args + i;

	/* Chew up trailing spaces. */
	while (*next == ' ')
	while (isspace(*next))
		next++;
	return next;
}
@@ -138,7 +139,7 @@ int parse_args(const char *name,
	DEBUGP("Parsing ARGS: %s\n", args);

	/* Chew leading spaces */
	while (*args == ' ')
	while (isspace(*args))
		args++;

	while (*args) {