Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
* 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)
This commit is contained in:
commit
2c9871de0a
3 changed files with 165 additions and 18 deletions
|
@ -128,7 +128,10 @@ extern struct module __this_module;
|
||||||
*/
|
*/
|
||||||
#define MODULE_LICENSE(_license) MODULE_INFO(license, _license)
|
#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)
|
#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
|
||||||
|
|
||||||
/* What your module does. */
|
/* What your module does. */
|
||||||
|
@ -308,10 +311,14 @@ struct module
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_KALLSYMS
|
#ifdef CONFIG_KALLSYMS
|
||||||
/* We keep the symbol and string tables for kallsyms. */
|
/*
|
||||||
Elf_Sym *symtab;
|
* We keep the symbol and string tables for kallsyms.
|
||||||
unsigned int num_symtab;
|
* The core_* fields below are temporary, loader-only (they
|
||||||
char *strtab;
|
* 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 */
|
/* Section attributes */
|
||||||
struct module_sect_attrs *sect_attrs;
|
struct module_sect_attrs *sect_attrs;
|
||||||
|
|
159
kernel/module.c
159
kernel/module.c
|
@ -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
|
#ifdef CONFIG_KALLSYMS
|
||||||
|
|
||||||
/* lookup symbol in given range of kernel_symbols */
|
/* lookup symbol in given range of kernel_symbols */
|
||||||
|
@ -1862,13 +1873,93 @@ static char elf_type(const Elf_Sym *sym,
|
||||||
return '?';
|
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,
|
static void add_kallsyms(struct module *mod,
|
||||||
Elf_Shdr *sechdrs,
|
Elf_Shdr *sechdrs,
|
||||||
|
unsigned int shnum,
|
||||||
unsigned int symindex,
|
unsigned int symindex,
|
||||||
unsigned int strindex,
|
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->symtab = (void *)sechdrs[symindex].sh_addr;
|
||||||
mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
|
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++)
|
for (i = 0; i < mod->num_symtab; i++)
|
||||||
mod->symtab[i].st_info
|
mod->symtab[i].st_info
|
||||||
= elf_type(&mod->symtab[i], sechdrs, secstrings, mod);
|
= 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
|
#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,
|
static inline void add_kallsyms(struct module *mod,
|
||||||
Elf_Shdr *sechdrs,
|
Elf_Shdr *sechdrs,
|
||||||
|
unsigned int shnum,
|
||||||
unsigned int symindex,
|
unsigned int symindex,
|
||||||
unsigned int strindex,
|
unsigned int strindex,
|
||||||
const char *secstrings)
|
unsigned long symoffs,
|
||||||
|
unsigned long stroffs,
|
||||||
|
const char *secstrings,
|
||||||
|
const unsigned long *strmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_KALLSYMS */
|
#endif /* CONFIG_KALLSYMS */
|
||||||
|
@ -1959,6 +2081,9 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
long err = 0;
|
long err = 0;
|
||||||
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
|
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
|
||||||
|
#ifdef CONFIG_KALLSYMS
|
||||||
|
unsigned long symoffs, stroffs, *strmap;
|
||||||
|
#endif
|
||||||
mm_segment_t old_fs;
|
mm_segment_t old_fs;
|
||||||
|
|
||||||
DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
|
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. */
|
/* Don't keep modinfo and version sections. */
|
||||||
sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
||||||
sechdrs[versindex].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. */
|
/* Check module struct version now, before we try to use module. */
|
||||||
if (!check_modstruct_version(sechdrs, versindex, mod)) {
|
if (!check_modstruct_version(sechdrs, versindex, mod)) {
|
||||||
|
@ -2080,6 +2200,13 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
goto free_hdr;
|
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)) {
|
if (find_module(mod->name)) {
|
||||||
err = -EEXIST;
|
err = -EEXIST;
|
||||||
goto free_mod;
|
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
|
this is done generically; there doesn't appear to be any
|
||||||
special cases for the architectures. */
|
special cases for the architectures. */
|
||||||
layout_sections(mod, hdr, sechdrs, secstrings);
|
layout_sections(mod, hdr, sechdrs, secstrings);
|
||||||
|
symoffs = layout_symtab(mod, sechdrs, symindex, strindex, hdr,
|
||||||
|
secstrings, &stroffs, strmap);
|
||||||
|
|
||||||
/* Do the allocs. */
|
/* Do the allocs. */
|
||||||
ptr = module_alloc_update_bounds(mod->core_size);
|
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,
|
percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr,
|
||||||
sechdrs[pcpuindex].sh_size);
|
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) {
|
if (!mod->taints) {
|
||||||
struct _ddebug *debug;
|
struct _ddebug *debug;
|
||||||
|
@ -2385,13 +2517,14 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
synchronize_sched();
|
synchronize_sched();
|
||||||
module_arch_cleanup(mod);
|
module_arch_cleanup(mod);
|
||||||
cleanup:
|
cleanup:
|
||||||
|
free_modinfo(mod);
|
||||||
kobject_del(&mod->mkobj.kobj);
|
kobject_del(&mod->mkobj.kobj);
|
||||||
kobject_put(&mod->mkobj.kobj);
|
kobject_put(&mod->mkobj.kobj);
|
||||||
free_unload:
|
free_unload:
|
||||||
module_unload_free(mod);
|
module_unload_free(mod);
|
||||||
#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
|
#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
|
||||||
free_init:
|
|
||||||
percpu_modfree(mod->refptr);
|
percpu_modfree(mod->refptr);
|
||||||
|
free_init:
|
||||||
#endif
|
#endif
|
||||||
module_free(mod, mod->module_init);
|
module_free(mod, mod->module_init);
|
||||||
free_core:
|
free_core:
|
||||||
|
@ -2402,6 +2535,7 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
percpu_modfree(percpu);
|
percpu_modfree(percpu);
|
||||||
free_mod:
|
free_mod:
|
||||||
kfree(args);
|
kfree(args);
|
||||||
|
kfree(strmap);
|
||||||
free_hdr:
|
free_hdr:
|
||||||
vfree(hdr);
|
vfree(hdr);
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
|
@ -2491,6 +2625,11 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
|
||||||
/* Drop initial reference. */
|
/* Drop initial reference. */
|
||||||
module_put(mod);
|
module_put(mod);
|
||||||
trim_init_extable(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);
|
module_free(mod, mod->module_init);
|
||||||
mod->module_init = NULL;
|
mod->module_init = NULL;
|
||||||
mod->init_size = 0;
|
mod->init_size = 0;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#define DEBUGP printk
|
#define DEBUGP printk
|
||||||
|
@ -87,7 +88,7 @@ static char *next_arg(char *args, char **param, char **val)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; args[i]; i++) {
|
for (i = 0; args[i]; i++) {
|
||||||
if (args[i] == ' ' && !in_quote)
|
if (isspace(args[i]) && !in_quote)
|
||||||
break;
|
break;
|
||||||
if (equals == 0) {
|
if (equals == 0) {
|
||||||
if (args[i] == '=')
|
if (args[i] == '=')
|
||||||
|
@ -121,7 +122,7 @@ static char *next_arg(char *args, char **param, char **val)
|
||||||
next = args + i;
|
next = args + i;
|
||||||
|
|
||||||
/* Chew up trailing spaces. */
|
/* Chew up trailing spaces. */
|
||||||
while (*next == ' ')
|
while (isspace(*next))
|
||||||
next++;
|
next++;
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
@ -138,7 +139,7 @@ int parse_args(const char *name,
|
||||||
DEBUGP("Parsing ARGS: %s\n", args);
|
DEBUGP("Parsing ARGS: %s\n", args);
|
||||||
|
|
||||||
/* Chew leading spaces */
|
/* Chew leading spaces */
|
||||||
while (*args == ' ')
|
while (isspace(*args))
|
||||||
args++;
|
args++;
|
||||||
|
|
||||||
while (*args) {
|
while (*args) {
|
||||||
|
|
Loading…
Reference in a new issue