Skip to content

Commit

Permalink
module: setup load info before module_sig_check()
Browse files Browse the repository at this point in the history
We want to be able to log the module name in early error messages, such as
when module signature verification fails.  Previously, the module name is
set in layout_and_allocate(), meaning that any error messages that happen
before (such as those in module_sig_check()) won't be logged with a module
name, which isn't terribly helpful.

In order to do this, reshuffle the order in load_module() and set up
load info earlier so that we can log the module name along with these
error messages. This requires splitting rewrite_section_headers() out of
setup_load_info().

While we're at it, clean up and split up the operations done in
layout_and_allocate(), setup_load_info(), and rewrite_section_headers()
more cleanly so these functions only perform what their names suggest.

Signed-off-by: Jessica Yu <[email protected]>
  • Loading branch information
Jessica Yu committed Jun 22, 2018
1 parent 81a0abd commit 5fdc7db
Showing 1 changed file with 43 additions and 34 deletions.
77 changes: 43 additions & 34 deletions kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -2488,7 +2488,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;
}
Expand Down Expand Up @@ -2928,17 +2932,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;
Expand All @@ -2955,16 +2949,18 @@ static int rewrite_section_headers(struct load_info *info, int flags)
static int setup_load_info(struct load_info *info, int flags)
{
unsigned int i;
int err;

/* 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;
/* 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++) {
Expand All @@ -2977,33 +2973,34 @@ static int 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 -ENOEXEC;
}
/* This is temporary: point mod into copy of data. */
info->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 = info->mod->name;

if (info->index.sym == 0) {
pr_warn("%s: module has no symbols (stripped?)\n", info->name);
return -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, info->mod))
return -ENOEXEC;

return 0;
}

Expand Down Expand Up @@ -3303,13 +3300,6 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
unsigned int ndx;
int err;

err = setup_load_info(info, flags);
if (err)
return ERR_PTR(err);

if (blacklisted(info->name))
return ERR_PTR(-EPERM);

err = check_modinfo(info->mod, info, flags);
if (err)
return ERR_PTR(err);
Expand Down Expand Up @@ -3657,17 +3647,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)) {
Expand Down

0 comments on commit 5fdc7db

Please sign in to comment.