|
@@ -307,24 +307,6 @@ int unregister_module_notifier(struct notifier_block *nb)
|
|
|
}
|
|
|
EXPORT_SYMBOL(unregister_module_notifier);
|
|
|
|
|
|
-struct load_info {
|
|
|
- const char *name;
|
|
|
- Elf_Ehdr *hdr;
|
|
|
- unsigned long len;
|
|
|
- Elf_Shdr *sechdrs;
|
|
|
- char *secstrings, *strtab;
|
|
|
- unsigned long symoffs, stroffs;
|
|
|
- struct _ddebug *debug;
|
|
|
- unsigned int num_debug;
|
|
|
- bool sig_ok;
|
|
|
-#ifdef CONFIG_KALLSYMS
|
|
|
- unsigned long mod_kallsyms_init_off;
|
|
|
-#endif
|
|
|
- struct {
|
|
|
- unsigned int sym, str, mod, vers, info, pcpu;
|
|
|
- } index;
|
|
|
-};
|
|
|
-
|
|
|
/*
|
|
|
* We require a truly strong try_module_get(): 0 means success.
|
|
|
* Otherwise an error is returned due to ongoing or failed
|
|
@@ -1339,14 +1321,12 @@ static inline int check_modstruct_version(const struct load_info *info,
|
|
|
* locking is necessary -- use preempt_disable() to placate lockdep.
|
|
|
*/
|
|
|
preempt_disable();
|
|
|
- if (!find_symbol(VMLINUX_SYMBOL_STR(module_layout), NULL,
|
|
|
- &crc, true, false)) {
|
|
|
+ if (!find_symbol("module_layout", NULL, &crc, true, false)) {
|
|
|
preempt_enable();
|
|
|
BUG();
|
|
|
}
|
|
|
preempt_enable();
|
|
|
- return check_version(info, VMLINUX_SYMBOL_STR(module_layout),
|
|
|
- mod, crc);
|
|
|
+ return check_version(info, "module_layout", mod, crc);
|
|
|
}
|
|
|
|
|
|
/* First part is kernel version, which we ignore if module has crcs. */
|
|
@@ -2059,21 +2039,19 @@ static int copy_module_elf(struct module *mod, struct load_info *info)
|
|
|
|
|
|
/* Elf section header table */
|
|
|
size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
|
|
|
- mod->klp_info->sechdrs = kmalloc(size, GFP_KERNEL);
|
|
|
+ mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
|
|
|
if (mod->klp_info->sechdrs == NULL) {
|
|
|
ret = -ENOMEM;
|
|
|
goto free_info;
|
|
|
}
|
|
|
- memcpy(mod->klp_info->sechdrs, info->sechdrs, size);
|
|
|
|
|
|
/* Elf section name string table */
|
|
|
size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
|
|
|
- mod->klp_info->secstrings = kmalloc(size, GFP_KERNEL);
|
|
|
+ mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
|
|
|
if (mod->klp_info->secstrings == NULL) {
|
|
|
ret = -ENOMEM;
|
|
|
goto free_sechdrs;
|
|
|
}
|
|
|
- memcpy(mod->klp_info->secstrings, info->secstrings, size);
|
|
|
|
|
|
/* Elf symbol section index */
|
|
|
symndx = info->index.sym;
|
|
@@ -2282,9 +2260,9 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
|
|
|
if (!ksym && ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
|
|
|
break;
|
|
|
|
|
|
- pr_warn("%s: Unknown symbol %s (err %li)\n",
|
|
|
- mod->name, name, PTR_ERR(ksym));
|
|
|
ret = PTR_ERR(ksym) ?: -ENOENT;
|
|
|
+ pr_warn("%s: Unknown symbol %s (err %d)\n",
|
|
|
+ mod->name, name, ret);
|
|
|
break;
|
|
|
|
|
|
default:
|
|
@@ -2486,7 +2464,11 @@ static char *get_modinfo(struct load_info *info, const char *tag)
|
|
|
Elf_Shdr *infosec = &info->sechdrs[info->index.info];
|
|
|
unsigned long size = infosec->sh_size;
|
|
|
|
|
|
- for (p = (char *)infosec->sh_addr; p; p = next_string(p, &size)) {
|
|
|
+ /*
|
|
|
+ * get_modinfo() calls made before rewrite_section_headers()
|
|
|
+ * must use sh_offset, as sh_addr isn't set!
|
|
|
+ */
|
|
|
+ for (p = (char *)info->hdr + infosec->sh_offset; p; p = next_string(p, &size)) {
|
|
|
if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
|
|
|
return p + taglen + 1;
|
|
|
}
|
|
@@ -2774,7 +2756,7 @@ static int module_sig_check(struct load_info *info, int flags)
|
|
|
memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
|
|
|
/* We truncate the module to discard the signature */
|
|
|
info->len -= markerlen;
|
|
|
- err = mod_verify_sig(mod, &info->len);
|
|
|
+ err = mod_verify_sig(mod, info);
|
|
|
}
|
|
|
|
|
|
if (!err) {
|
|
@@ -2926,17 +2908,7 @@ static int rewrite_section_headers(struct load_info *info, int flags)
|
|
|
}
|
|
|
|
|
|
/* Track but don't keep modinfo and version sections. */
|
|
|
- if (flags & MODULE_INIT_IGNORE_MODVERSIONS)
|
|
|
- info->index.vers = 0; /* Pretend no __versions section! */
|
|
|
- else
|
|
|
- info->index.vers = find_sec(info, "__versions");
|
|
|
info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
|
|
-
|
|
|
- info->index.info = find_sec(info, ".modinfo");
|
|
|
- if (!info->index.info)
|
|
|
- info->name = "(missing .modinfo section)";
|
|
|
- else
|
|
|
- info->name = get_modinfo(info, "name");
|
|
|
info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
|
|
|
|
|
return 0;
|
|
@@ -2947,23 +2919,24 @@ static int rewrite_section_headers(struct load_info *info, int flags)
|
|
|
* search for module section index etc), and do some basic section
|
|
|
* verification.
|
|
|
*
|
|
|
- * Return the temporary module pointer (we'll replace it with the final
|
|
|
- * one when we move the module sections around).
|
|
|
+ * Set info->mod to the temporary copy of the module in info->hdr. The final one
|
|
|
+ * will be allocated in move_module().
|
|
|
*/
|
|
|
-static struct module *setup_load_info(struct load_info *info, int flags)
|
|
|
+static int setup_load_info(struct load_info *info, int flags)
|
|
|
{
|
|
|
unsigned int i;
|
|
|
- int err;
|
|
|
- struct module *mod;
|
|
|
|
|
|
/* Set up the convenience variables */
|
|
|
info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
|
|
|
info->secstrings = (void *)info->hdr
|
|
|
+ info->sechdrs[info->hdr->e_shstrndx].sh_offset;
|
|
|
|
|
|
- err = rewrite_section_headers(info, flags);
|
|
|
- if (err)
|
|
|
- return ERR_PTR(err);
|
|
|
+ /* Try to find a name early so we can log errors with a module name */
|
|
|
+ info->index.info = find_sec(info, ".modinfo");
|
|
|
+ if (!info->index.info)
|
|
|
+ info->name = "(missing .modinfo section)";
|
|
|
+ else
|
|
|
+ info->name = get_modinfo(info, "name");
|
|
|
|
|
|
/* Find internal symbols and strings. */
|
|
|
for (i = 1; i < info->hdr->e_shnum; i++) {
|
|
@@ -2976,34 +2949,35 @@ static struct module *setup_load_info(struct load_info *info, int flags)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (info->index.sym == 0) {
|
|
|
+ pr_warn("%s: module has no symbols (stripped?)\n", info->name);
|
|
|
+ return -ENOEXEC;
|
|
|
+ }
|
|
|
+
|
|
|
info->index.mod = find_sec(info, ".gnu.linkonce.this_module");
|
|
|
if (!info->index.mod) {
|
|
|
pr_warn("%s: No module found in object\n",
|
|
|
info->name ?: "(missing .modinfo name field)");
|
|
|
- return ERR_PTR(-ENOEXEC);
|
|
|
+ return -ENOEXEC;
|
|
|
}
|
|
|
/* This is temporary: point mod into copy of data. */
|
|
|
- mod = (void *)info->sechdrs[info->index.mod].sh_addr;
|
|
|
+ info->mod = (void *)info->hdr + info->sechdrs[info->index.mod].sh_offset;
|
|
|
|
|
|
/*
|
|
|
- * If we didn't load the .modinfo 'name' field, fall back to
|
|
|
+ * If we didn't load the .modinfo 'name' field earlier, fall back to
|
|
|
* on-disk struct mod 'name' field.
|
|
|
*/
|
|
|
if (!info->name)
|
|
|
- info->name = mod->name;
|
|
|
+ info->name = info->mod->name;
|
|
|
|
|
|
- if (info->index.sym == 0) {
|
|
|
- pr_warn("%s: module has no symbols (stripped?)\n", info->name);
|
|
|
- return ERR_PTR(-ENOEXEC);
|
|
|
- }
|
|
|
+ if (flags & MODULE_INIT_IGNORE_MODVERSIONS)
|
|
|
+ info->index.vers = 0; /* Pretend no __versions section! */
|
|
|
+ else
|
|
|
+ info->index.vers = find_sec(info, "__versions");
|
|
|
|
|
|
info->index.pcpu = find_pcpusec(info);
|
|
|
|
|
|
- /* Check module struct version now, before we try to use module. */
|
|
|
- if (!check_modstruct_version(info, mod))
|
|
|
- return ERR_PTR(-ENOEXEC);
|
|
|
-
|
|
|
- return mod;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static int check_modinfo(struct module *mod, struct load_info *info, int flags)
|
|
@@ -3298,25 +3272,17 @@ core_param(module_blacklist, module_blacklist, charp, 0400);
|
|
|
|
|
|
static struct module *layout_and_allocate(struct load_info *info, int flags)
|
|
|
{
|
|
|
- /* Module within temporary copy. */
|
|
|
struct module *mod;
|
|
|
unsigned int ndx;
|
|
|
int err;
|
|
|
|
|
|
- mod = setup_load_info(info, flags);
|
|
|
- if (IS_ERR(mod))
|
|
|
- return mod;
|
|
|
-
|
|
|
- if (blacklisted(info->name))
|
|
|
- return ERR_PTR(-EPERM);
|
|
|
-
|
|
|
- err = check_modinfo(mod, info, flags);
|
|
|
+ err = check_modinfo(info->mod, info, flags);
|
|
|
if (err)
|
|
|
return ERR_PTR(err);
|
|
|
|
|
|
/* Allow arches to frob section contents and sizes. */
|
|
|
err = module_frob_arch_sections(info->hdr, info->sechdrs,
|
|
|
- info->secstrings, mod);
|
|
|
+ info->secstrings, info->mod);
|
|
|
if (err < 0)
|
|
|
return ERR_PTR(err);
|
|
|
|
|
@@ -3335,11 +3301,11 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
|
|
|
/* Determine total sizes, and put offsets in sh_entsize. For now
|
|
|
this is done generically; there doesn't appear to be any
|
|
|
special cases for the architectures. */
|
|
|
- layout_sections(mod, info);
|
|
|
- layout_symtab(mod, info);
|
|
|
+ layout_sections(info->mod, info);
|
|
|
+ layout_symtab(info->mod, info);
|
|
|
|
|
|
/* Allocate and move to the final place */
|
|
|
- err = move_module(mod, info);
|
|
|
+ err = move_module(info->mod, info);
|
|
|
if (err)
|
|
|
return ERR_PTR(err);
|
|
|
|
|
@@ -3657,17 +3623,36 @@ static int load_module(struct load_info *info, const char __user *uargs,
|
|
|
int flags)
|
|
|
{
|
|
|
struct module *mod;
|
|
|
- long err;
|
|
|
+ long err = 0;
|
|
|
char *after_dashes;
|
|
|
|
|
|
+ err = elf_header_check(info);
|
|
|
+ if (err)
|
|
|
+ goto free_copy;
|
|
|
+
|
|
|
+ err = setup_load_info(info, flags);
|
|
|
+ if (err)
|
|
|
+ goto free_copy;
|
|
|
+
|
|
|
+ if (blacklisted(info->name)) {
|
|
|
+ err = -EPERM;
|
|
|
+ goto free_copy;
|
|
|
+ }
|
|
|
+
|
|
|
err = module_sig_check(info, flags);
|
|
|
if (err)
|
|
|
goto free_copy;
|
|
|
|
|
|
- err = elf_header_check(info);
|
|
|
+ err = rewrite_section_headers(info, flags);
|
|
|
if (err)
|
|
|
goto free_copy;
|
|
|
|
|
|
+ /* Check module struct version now, before we try to use module. */
|
|
|
+ if (!check_modstruct_version(info, info->mod)) {
|
|
|
+ err = -ENOEXEC;
|
|
|
+ goto free_copy;
|
|
|
+ }
|
|
|
+
|
|
|
/* Figure out module layout, and allocate all the memory. */
|
|
|
mod = layout_and_allocate(info, flags);
|
|
|
if (IS_ERR(mod)) {
|
|
@@ -4067,7 +4052,7 @@ static unsigned long mod_find_symname(struct module *mod, const char *name)
|
|
|
|
|
|
for (i = 0; i < kallsyms->num_symtab; i++)
|
|
|
if (strcmp(name, symname(kallsyms, i)) == 0 &&
|
|
|
- kallsyms->symtab[i].st_info != 'U')
|
|
|
+ kallsyms->symtab[i].st_shndx != SHN_UNDEF)
|
|
|
return kallsyms->symtab[i].st_value;
|
|
|
return 0;
|
|
|
}
|
|
@@ -4113,6 +4098,10 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
|
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
|
continue;
|
|
|
for (i = 0; i < kallsyms->num_symtab; i++) {
|
|
|
+
|
|
|
+ if (kallsyms->symtab[i].st_shndx == SHN_UNDEF)
|
|
|
+ continue;
|
|
|
+
|
|
|
ret = fn(data, symname(kallsyms, i),
|
|
|
mod, kallsyms->symtab[i].st_value);
|
|
|
if (ret != 0)
|