module: setup load info before module_sig_check()
authorJessica Yu <jeyu@kernel.org>
Fri, 22 Jun 2018 12:00:01 +0000 (14:00 +0200)
committerJessica Yu <jeyu@kernel.org>
Fri, 22 Jun 2018 12:00:01 +0000 (14:00 +0200)
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 <jeyu@kernel.org>
kernel/module.c

index 3ed4aaa646dce8c4dfa80779eb171c9ecfc463d2..0ad0bb58e116b33ac735c3918eee7c17fbe45e8e 100644 (file)
@@ -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;
        }
@@ -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;
@@ -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++) {
@@ -2977,6 +2973,11 @@ 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",
@@ -2984,26 +2985,22 @@ static int setup_load_info(struct load_info *info, int flags)
                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;
 }
 
@@ -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);
@@ -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)) {