module: refactor out section header rewriting
Rusty Russell [Thu, 5 Aug 2010 18:59:06 +0000 (12:59 -0600)]
Put all the "rewrite and check section headers" in one place.  This
adds another iteration over the sections, but it's far clearer.  We
iterate once for every find_section() so we already iterate over many
times.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

kernel/module.c

index cb40a4e..91f3ebe 100644 (file)
@@ -2158,6 +2158,7 @@ struct load_info {
        } index;
 };
 
+/* Sets info->hdr and info->len. */
 static int copy_and_check(struct load_info *info, const void __user *umod, unsigned long len)
 {
        int err;
@@ -2199,6 +2200,39 @@ free_hdr:
        return err;
 }
 
+static int rewrite_section_headers(struct load_info *info)
+{
+       unsigned int i;
+
+       /* This should always be true, but let's be sure. */
+       info->sechdrs[0].sh_addr = 0;
+
+       for (i = 1; i < info->hdr->e_shnum; i++) {
+               Elf_Shdr *shdr = &info->sechdrs[i];
+               if (shdr->sh_type != SHT_NOBITS
+                   && info->len < shdr->sh_offset + shdr->sh_size) {
+                       printk(KERN_ERR "Module len %lu truncated\n",
+                              info->len);
+                       return -ENOEXEC;
+               }
+
+               /* Mark all sections sh_addr with their address in the
+                  temporary image. */
+               shdr->sh_addr = (size_t)info->hdr + shdr->sh_offset;
+
+#ifndef CONFIG_MODULE_UNLOAD
+               /* Don't load .exit sections */
+               if (strstarts(info->secstrings+shdr->sh_name, ".exit"))
+                       shdr->sh_flags &= ~(unsigned long)SHF_ALLOC;
+#endif
+               /* Don't keep modinfo and version sections. */
+               if (!strcmp(info->secstrings+shdr->sh_name, "__versions")
+                   || !strcmp(info->secstrings+shdr->sh_name, ".modinfo"))
+                       shdr->sh_flags &= ~(unsigned long)SHF_ALLOC;
+       }
+       return 0;
+}
+
 /*
  * Set up our basic convenience variables (pointers to section headers,
  * search for module section index etc), and do some basic section
@@ -2210,33 +2244,27 @@ free_hdr:
 static struct module *setup_load_info(struct load_info *info)
 {
        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;
-       info->sechdrs[0].sh_addr = 0;
-
-       for (i = 1; i < info->hdr->e_shnum; i++) {
-               if (info->sechdrs[i].sh_type != SHT_NOBITS
-                   && info->len < info->sechdrs[i].sh_offset + info->sechdrs[i].sh_size)
-                       goto truncated;
+       info->secstrings = (void *)info->hdr
+               + info->sechdrs[info->hdr->e_shstrndx].sh_offset;
 
-               /* Mark all sections sh_addr with their address in the
-                  temporary image. */
-               info->sechdrs[i].sh_addr = (size_t)info->hdr + info->sechdrs[i].sh_offset;
+       err = rewrite_section_headers(info);
+       if (err)
+               return ERR_PTR(err);
 
-               /* Internal symbols and strings. */
+       /* Find internal symbols and strings. */
+       for (i = 1; i < info->hdr->e_shnum; i++) {
                if (info->sechdrs[i].sh_type == SHT_SYMTAB) {
                        info->index.sym = i;
                        info->index.str = info->sechdrs[i].sh_link;
-                       info->strtab = (char *)info->hdr + info->sechdrs[info->index.str].sh_offset;
+                       info->strtab = (char *)info->hdr
+                               + info->sechdrs[info->index.str].sh_offset;
+                       break;
                }
-#ifndef CONFIG_MODULE_UNLOAD
-               /* Don't load .exit sections */
-               if (strstarts(info->secstrings+info->sechdrs[i].sh_name, ".exit"))
-                       info->sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
-#endif
        }
 
        info->index.mod = find_sec(info->hdr, info->sechdrs, info->secstrings,
@@ -2258,19 +2286,11 @@ static struct module *setup_load_info(struct load_info *info)
        info->index.info = find_sec(info->hdr, info->sechdrs, info->secstrings, ".modinfo");
        info->index.pcpu = find_pcpusec(info->hdr, info->sechdrs, info->secstrings);
 
-       /* Don't keep modinfo and version sections. */
-       info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
-       info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
-
        /* Check module struct version now, before we try to use module. */
        if (!check_modstruct_version(info->sechdrs, info->index.vers, mod))
                return ERR_PTR(-ENOEXEC);
 
        return mod;
-
- truncated:
-       printk(KERN_ERR "Module len %lu truncated\n", info->len);
-       return ERR_PTR(-ENOEXEC);
 }
 
 static int check_modinfo(struct module *mod,