module: add load_info
[deliverable/linux.git] / kernel / module.c
index 5d2d28197c827a840d98357c11c1e16b3dce92a2..cb40a4e64a0eaeda7c4f8b09b7e00851bef74d81 100644 (file)
@@ -227,7 +227,7 @@ bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
                            unsigned int symnum, void *data), void *data)
 {
        struct module *mod;
-       const struct symsearch arr[] = {
+       static const struct symsearch arr[] = {
                { __start___ksymtab, __stop___ksymtab, __start___kcrctab,
                  NOT_GPL_ONLY, false },
                { __start___ksymtab_gpl, __stop___ksymtab_gpl,
@@ -524,21 +524,21 @@ static char last_unloaded_module[MODULE_NAME_LEN+1];
 EXPORT_TRACEPOINT_SYMBOL(module_get);
 
 /* Init the unload section of the module. */
-static void module_unload_init(struct module *mod)
+static int module_unload_init(struct module *mod)
 {
-       int cpu;
+       mod->refptr = alloc_percpu(struct module_ref);
+       if (!mod->refptr)
+               return -ENOMEM;
 
        INIT_LIST_HEAD(&mod->source_list);
        INIT_LIST_HEAD(&mod->target_list);
-       for_each_possible_cpu(cpu) {
-               per_cpu_ptr(mod->refptr, cpu)->incs = 0;
-               per_cpu_ptr(mod->refptr, cpu)->decs = 0;
-       }
 
        /* Hold reference count during initialization. */
        __this_cpu_write(mod->refptr->incs, 1);
        /* Backwards compatibility macros put refcount during init. */
        mod->waiter = current;
+
+       return 0;
 }
 
 /* Does a already use b? */
@@ -618,6 +618,8 @@ static void module_unload_free(struct module *mod)
                kfree(use);
        }
        mutex_unlock(&module_mutex);
+
+       free_percpu(mod->refptr);
 }
 
 #ifdef CONFIG_MODULE_FORCE_UNLOAD
@@ -787,7 +789,6 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
 
        /* Store the name of the last unloaded module for diagnostic purposes */
        strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
-       ddebug_remove_module(mod->name);
 
        free_module(mod);
        return 0;
@@ -892,8 +893,9 @@ int ref_module(struct module *a, struct module *b)
 }
 EXPORT_SYMBOL_GPL(ref_module);
 
-static inline void module_unload_init(struct module *mod)
+static inline int module_unload_init(struct module *mod)
 {
+       return 0;
 }
 #endif /* CONFIG_MODULE_UNLOAD */
 
@@ -1550,6 +1552,9 @@ static void free_module(struct module *mod)
        remove_sect_attrs(mod);
        mod_kobject_remove(mod);
 
+       /* Remove dynamic debug info */
+       ddebug_remove_module(mod->name);
+
        /* Arch-specific cleanup. */
        module_arch_cleanup(mod);
 
@@ -1563,10 +1568,7 @@ static void free_module(struct module *mod)
        module_free(mod, mod->module_init);
        kfree(mod->args);
        percpu_modfree(mod);
-#if defined(CONFIG_MODULE_UNLOAD)
-       if (mod->refptr)
-               free_percpu(mod->refptr);
-#endif
+
        /* Free lock-classes: */
        lockdep_free_key_range(mod->module_core, mod->core_size);
 
@@ -1696,6 +1698,39 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
        return ret;
 }
 
+static int apply_relocations(struct module *mod,
+                            Elf_Ehdr *hdr,
+                            Elf_Shdr *sechdrs,
+                            unsigned int symindex,
+                            unsigned int strindex)
+{
+       unsigned int i;
+       int err = 0;
+
+       /* Now do relocations. */
+       for (i = 1; i < hdr->e_shnum; i++) {
+               const char *strtab = (char *)sechdrs[strindex].sh_addr;
+               unsigned int info = sechdrs[i].sh_info;
+
+               /* Not a valid relocation section? */
+               if (info >= hdr->e_shnum)
+                       continue;
+
+               /* Don't bother with non-allocated sections */
+               if (!(sechdrs[info].sh_flags & SHF_ALLOC))
+                       continue;
+
+               if (sechdrs[i].sh_type == SHT_REL)
+                       err = apply_relocate(sechdrs, strtab, symindex, i, mod);
+               else if (sechdrs[i].sh_type == SHT_RELA)
+                       err = apply_relocate_add(sechdrs, strtab, symindex, i,
+                                                mod);
+               if (err < 0)
+                       break;
+       }
+       return err;
+}
+
 /* Additional bytes needed by arch in front of individual sections */
 unsigned int __weak arch_mod_section_prepend(struct module *mod,
                                             unsigned int section)
@@ -1807,7 +1842,7 @@ static char *next_string(char *string, unsigned long *secsize)
        return string;
 }
 
-static char *get_modinfo(Elf_Shdr *sechdrs,
+static char *get_modinfo(const Elf_Shdr *sechdrs,
                         unsigned int info,
                         const char *tag)
 {
@@ -2086,7 +2121,8 @@ static void *module_alloc_update_bounds(unsigned long size)
 
 #ifdef CONFIG_DEBUG_KMEMLEAK
 static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
-                                Elf_Shdr *sechdrs, char *secstrings)
+                                const Elf_Shdr *sechdrs,
+                                const char *secstrings)
 {
        unsigned int i;
 
@@ -2106,44 +2142,34 @@ static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
 }
 #else
 static inline void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
-                                       Elf_Shdr *sechdrs, char *secstrings)
+                                       Elf_Shdr *sechdrs,
+                                       const char *secstrings)
 {
 }
 #endif
 
-/* Allocate and load the module: note that size of section 0 is always
-   zero, and we rely on this for optional sections. */
-static noinline struct module *load_module(void __user *umod,
-                                 unsigned long len,
-                                 const char __user *uargs)
-{
+struct load_info {
        Elf_Ehdr *hdr;
+       unsigned long len;
        Elf_Shdr *sechdrs;
-       char *secstrings, *args, *modmagic, *strtab = NULL;
-       char *staging;
-       unsigned int i;
-       unsigned int symindex = 0;
-       unsigned int strindex = 0;
-       unsigned int modindex, versindex, infoindex, pcpuindex;
-       struct module *mod;
-       long err = 0;
-       void *ptr = NULL; /* Stops spurious gcc warning */
-       unsigned long symoffs, stroffs, *strmap;
-       void __percpu *percpu;
-       struct _ddebug *debug = NULL;
-       unsigned int num_debug = 0;
+       char *secstrings, *args, *strtab;
+       struct {
+               unsigned int sym, str, mod, vers, info, pcpu;
+       } index;
+};
 
-       mm_segment_t old_fs;
+static int copy_and_check(struct load_info *info, const void __user *umod, unsigned long len)
+{
+       int err;
+       Elf_Ehdr *hdr;
 
-       DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
-              umod, len, uargs);
        if (len < sizeof(*hdr))
-               return ERR_PTR(-ENOEXEC);
+               return -ENOEXEC;
 
        /* Suck in entire file: we'll want most of it. */
        /* vmalloc barfs on "unusual" numbers.  Check here */
        if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
 
        if (copy_from_user(hdr, umod, len) != 0) {
                err = -EFAULT;
@@ -2151,135 +2177,208 @@ static noinline struct module *load_module(void __user *umod,
        }
 
        /* Sanity checks against insmoding binaries or wrong arch,
-           weird elf version */
+          weird elf version */
        if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
            || hdr->e_type != ET_REL
            || !elf_check_arch(hdr)
-           || hdr->e_shentsize != sizeof(*sechdrs)) {
+           || hdr->e_shentsize != sizeof(Elf_Shdr)) {
                err = -ENOEXEC;
                goto free_hdr;
        }
 
-       if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr))
-               goto truncated;
+       if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
+               err = -ENOEXEC;
+               goto free_hdr;
+       }
+       info->hdr = hdr;
+       info->len = len;
+       return 0;
 
-       /* Convenience variables */
-       sechdrs = (void *)hdr + hdr->e_shoff;
-       secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
-       sechdrs[0].sh_addr = 0;
+free_hdr:
+       vfree(hdr);
+       return err;
+}
 
-       for (i = 1; i < hdr->e_shnum; i++) {
-               if (sechdrs[i].sh_type != SHT_NOBITS
-                   && len < sechdrs[i].sh_offset + sechdrs[i].sh_size)
+/*
+ * Set up our basic convenience variables (pointers to section headers,
+ * 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).
+ */
+static struct module *setup_load_info(struct load_info *info)
+{
+       unsigned int i;
+       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;
 
                /* Mark all sections sh_addr with their address in the
                   temporary image. */
-               sechdrs[i].sh_addr = (size_t)hdr + sechdrs[i].sh_offset;
+               info->sechdrs[i].sh_addr = (size_t)info->hdr + info->sechdrs[i].sh_offset;
 
                /* Internal symbols and strings. */
-               if (sechdrs[i].sh_type == SHT_SYMTAB) {
-                       symindex = i;
-                       strindex = sechdrs[i].sh_link;
-                       strtab = (char *)hdr + sechdrs[strindex].sh_offset;
+               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;
                }
 #ifndef CONFIG_MODULE_UNLOAD
                /* Don't load .exit sections */
-               if (strstarts(secstrings+sechdrs[i].sh_name, ".exit"))
-                       sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
+               if (strstarts(info->secstrings+info->sechdrs[i].sh_name, ".exit"))
+                       info->sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
 #endif
        }
 
-       modindex = find_sec(hdr, sechdrs, secstrings,
+       info->index.mod = find_sec(info->hdr, info->sechdrs, info->secstrings,
                            ".gnu.linkonce.this_module");
-       if (!modindex) {
+       if (!info->index.mod) {
                printk(KERN_WARNING "No module found in object\n");
-               err = -ENOEXEC;
-               goto free_hdr;
+               return ERR_PTR(-ENOEXEC);
        }
        /* This is temporary: point mod into copy of data. */
-       mod = (void *)sechdrs[modindex].sh_addr;
+       mod = (void *)info->sechdrs[info->index.mod].sh_addr;
 
-       if (symindex == 0) {
+       if (info->index.sym == 0) {
                printk(KERN_WARNING "%s: module has no symbols (stripped?)\n",
                       mod->name);
-               err = -ENOEXEC;
-               goto free_hdr;
+               return ERR_PTR(-ENOEXEC);
        }
 
-       versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
-       infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
-       pcpuindex = find_pcpusec(hdr, sechdrs, secstrings);
+       info->index.vers = find_sec(info->hdr, info->sechdrs, info->secstrings, "__versions");
+       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. */
-       sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
-       sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
+       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(sechdrs, versindex, mod)) {
-               err = -ENOEXEC;
-               goto free_hdr;
-       }
+       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,
+                        const Elf_Shdr *sechdrs,
+                        unsigned int infoindex, unsigned int versindex)
+{
+       const char *modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
+       int err;
 
-       modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
        /* This is allowed: modprobe --force will invalidate it. */
        if (!modmagic) {
                err = try_to_force_load(mod, "bad vermagic");
                if (err)
-                       goto free_hdr;
+                       return err;
        } else if (!same_magic(modmagic, vermagic, versindex)) {
                printk(KERN_ERR "%s: version magic '%s' should be '%s'\n",
                       mod->name, modmagic, vermagic);
-               err = -ENOEXEC;
-               goto free_hdr;
+               return -ENOEXEC;
        }
 
-       staging = get_modinfo(sechdrs, infoindex, "staging");
-       if (staging) {
+       if (get_modinfo(sechdrs, infoindex, "staging")) {
                add_taint_module(mod, TAINT_CRAP);
                printk(KERN_WARNING "%s: module is from the staging directory,"
                       " the quality is unknown, you have been warned.\n",
                       mod->name);
        }
 
-       /* Now copy in args */
-       args = strndup_user(uargs, ~0UL >> 1);
-       if (IS_ERR(args)) {
-               err = PTR_ERR(args);
-               goto free_hdr;
-       }
+       /* Set up license info based on the info section */
+       set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
 
-       strmap = kzalloc(BITS_TO_LONGS(sechdrs[strindex].sh_size)
-                        * sizeof(long), GFP_KERNEL);
-       if (!strmap) {
-               err = -ENOMEM;
-               goto free_mod;
-       }
+       return 0;
+}
 
-       mod->state = MODULE_STATE_COMING;
+static void find_module_sections(struct module *mod, Elf_Ehdr *hdr,
+                                Elf_Shdr *sechdrs, const char *secstrings)
+{
+       mod->kp = section_objs(hdr, sechdrs, secstrings, "__param",
+                              sizeof(*mod->kp), &mod->num_kp);
+       mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab",
+                                sizeof(*mod->syms), &mod->num_syms);
+       mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab");
+       mod->gpl_syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab_gpl",
+                                    sizeof(*mod->gpl_syms),
+                                    &mod->num_gpl_syms);
+       mod->gpl_crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab_gpl");
+       mod->gpl_future_syms = section_objs(hdr, sechdrs, secstrings,
+                                           "__ksymtab_gpl_future",
+                                           sizeof(*mod->gpl_future_syms),
+                                           &mod->num_gpl_future_syms);
+       mod->gpl_future_crcs = section_addr(hdr, sechdrs, secstrings,
+                                           "__kcrctab_gpl_future");
 
-       /* Allow arches to frob section contents and sizes.  */
-       err = module_frob_arch_sections(hdr, sechdrs, secstrings, mod);
-       if (err < 0)
-               goto free_mod;
+#ifdef CONFIG_UNUSED_SYMBOLS
+       mod->unused_syms = section_objs(hdr, sechdrs, secstrings,
+                                       "__ksymtab_unused",
+                                       sizeof(*mod->unused_syms),
+                                       &mod->num_unused_syms);
+       mod->unused_crcs = section_addr(hdr, sechdrs, secstrings,
+                                       "__kcrctab_unused");
+       mod->unused_gpl_syms = section_objs(hdr, sechdrs, secstrings,
+                                           "__ksymtab_unused_gpl",
+                                           sizeof(*mod->unused_gpl_syms),
+                                           &mod->num_unused_gpl_syms);
+       mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings,
+                                           "__kcrctab_unused_gpl");
+#endif
+#ifdef CONFIG_CONSTRUCTORS
+       mod->ctors = section_objs(hdr, sechdrs, secstrings, ".ctors",
+                                 sizeof(*mod->ctors), &mod->num_ctors);
+#endif
 
-       if (pcpuindex) {
-               /* We have a special allocation for this section. */
-               err = percpu_modalloc(mod, sechdrs[pcpuindex].sh_size,
-                                     sechdrs[pcpuindex].sh_addralign);
-               if (err)
-                       goto free_mod;
-               sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
-       }
-       /* Keep this around for failure path. */
-       percpu = mod_percpu(mod);
+#ifdef CONFIG_TRACEPOINTS
+       mod->tracepoints = section_objs(hdr, sechdrs, secstrings,
+                                       "__tracepoints",
+                                       sizeof(*mod->tracepoints),
+                                       &mod->num_tracepoints);
+#endif
+#ifdef CONFIG_EVENT_TRACING
+       mod->trace_events = section_objs(hdr, sechdrs, secstrings,
+                                        "_ftrace_events",
+                                        sizeof(*mod->trace_events),
+                                        &mod->num_trace_events);
+       /*
+        * This section contains pointers to allocated objects in the trace
+        * code and not scanning it leads to false positives.
+        */
+       kmemleak_scan_area(mod->trace_events, sizeof(*mod->trace_events) *
+                          mod->num_trace_events, GFP_KERNEL);
+#endif
+#ifdef CONFIG_FTRACE_MCOUNT_RECORD
+       /* sechdrs[0].sh_size is always zero */
+       mod->ftrace_callsites = section_objs(hdr, sechdrs, secstrings,
+                                            "__mcount_loc",
+                                            sizeof(*mod->ftrace_callsites),
+                                            &mod->num_ftrace_callsites);
+#endif
 
-       /* 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, hdr, sechdrs, secstrings);
-       symoffs = layout_symtab(mod, sechdrs, symindex, strindex, hdr,
-                               secstrings, &stroffs, strmap);
+       if (section_addr(hdr, sechdrs, secstrings, "__obsparm"))
+               printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
+                      mod->name);
+}
+
+static struct module *move_module(struct module *mod,
+                                 Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
+                                 const char *secstrings, unsigned modindex)
+{
+       int i;
+       void *ptr;
 
        /* Do the allocs. */
        ptr = module_alloc_update_bounds(mod->core_size);
@@ -2289,10 +2388,9 @@ static noinline struct module *load_module(void __user *umod,
         * leak.
         */
        kmemleak_not_leak(ptr);
-       if (!ptr) {
-               err = -ENOMEM;
-               goto free_percpu;
-       }
+       if (!ptr)
+               return ERR_PTR(-ENOMEM);
+
        memset(ptr, 0, mod->core_size);
        mod->module_core = ptr;
 
@@ -2305,8 +2403,8 @@ static noinline struct module *load_module(void __user *umod,
         */
        kmemleak_ignore(ptr);
        if (!ptr && mod->init_size) {
-               err = -ENOMEM;
-               goto free_core;
+               module_free(mod, mod->module_core);
+               return ERR_PTR(-ENOMEM);
        }
        memset(ptr, 0, mod->init_size);
        mod->module_init = ptr;
@@ -2330,25 +2428,18 @@ static noinline struct module *load_module(void __user *umod,
                               sechdrs[i].sh_size);
                /* Update sh_addr to point to copy in image. */
                sechdrs[i].sh_addr = (unsigned long)dest;
-               DEBUGP("\t0x%lx %s\n", sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name);
+               DEBUGP("\t0x%lx %s\n",
+                      sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name);
        }
        /* Module has been moved. */
        mod = (void *)sechdrs[modindex].sh_addr;
        kmemleak_load_module(mod, hdr, sechdrs, secstrings);
+       return mod;
+}
 
-#if defined(CONFIG_MODULE_UNLOAD)
-       mod->refptr = alloc_percpu(struct module_ref);
-       if (!mod->refptr) {
-               err = -ENOMEM;
-               goto free_init;
-       }
-#endif
-       /* Now we've moved module, initialize linked lists, etc. */
-       module_unload_init(mod);
-
-       /* Set up license info based on the info section */
-       set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
-
+static int check_module_license_and_versions(struct module *mod,
+                                            Elf_Shdr *sechdrs)
+{
        /*
         * ndiswrapper is under GPL by itself, but loads proprietary modules.
         * Don't use add_taint_module(), as it would prevent ndiswrapper from
@@ -2361,77 +2452,6 @@ static noinline struct module *load_module(void __user *umod,
        if (strcmp(mod->name, "driverloader") == 0)
                add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
 
-       /* Set up MODINFO_ATTR fields */
-       setup_modinfo(mod, sechdrs, infoindex);
-
-       /* Fix up syms, so that st_value is a pointer to location. */
-       err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
-                              mod);
-       if (err < 0)
-               goto cleanup;
-
-       /* Now we've got everything in the final locations, we can
-        * find optional sections. */
-       mod->kp = section_objs(hdr, sechdrs, secstrings, "__param",
-                              sizeof(*mod->kp), &mod->num_kp);
-       mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab",
-                                sizeof(*mod->syms), &mod->num_syms);
-       mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab");
-       mod->gpl_syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab_gpl",
-                                    sizeof(*mod->gpl_syms),
-                                    &mod->num_gpl_syms);
-       mod->gpl_crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab_gpl");
-       mod->gpl_future_syms = section_objs(hdr, sechdrs, secstrings,
-                                           "__ksymtab_gpl_future",
-                                           sizeof(*mod->gpl_future_syms),
-                                           &mod->num_gpl_future_syms);
-       mod->gpl_future_crcs = section_addr(hdr, sechdrs, secstrings,
-                                           "__kcrctab_gpl_future");
-
-#ifdef CONFIG_UNUSED_SYMBOLS
-       mod->unused_syms = section_objs(hdr, sechdrs, secstrings,
-                                       "__ksymtab_unused",
-                                       sizeof(*mod->unused_syms),
-                                       &mod->num_unused_syms);
-       mod->unused_crcs = section_addr(hdr, sechdrs, secstrings,
-                                       "__kcrctab_unused");
-       mod->unused_gpl_syms = section_objs(hdr, sechdrs, secstrings,
-                                           "__ksymtab_unused_gpl",
-                                           sizeof(*mod->unused_gpl_syms),
-                                           &mod->num_unused_gpl_syms);
-       mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings,
-                                           "__kcrctab_unused_gpl");
-#endif
-#ifdef CONFIG_CONSTRUCTORS
-       mod->ctors = section_objs(hdr, sechdrs, secstrings, ".ctors",
-                                 sizeof(*mod->ctors), &mod->num_ctors);
-#endif
-
-#ifdef CONFIG_TRACEPOINTS
-       mod->tracepoints = section_objs(hdr, sechdrs, secstrings,
-                                       "__tracepoints",
-                                       sizeof(*mod->tracepoints),
-                                       &mod->num_tracepoints);
-#endif
-#ifdef CONFIG_EVENT_TRACING
-       mod->trace_events = section_objs(hdr, sechdrs, secstrings,
-                                        "_ftrace_events",
-                                        sizeof(*mod->trace_events),
-                                        &mod->num_trace_events);
-       /*
-        * This section contains pointers to allocated objects in the trace
-        * code and not scanning it leads to false positives.
-        */
-       kmemleak_scan_area(mod->trace_events, sizeof(*mod->trace_events) *
-                          mod->num_trace_events, GFP_KERNEL);
-#endif
-#ifdef CONFIG_FTRACE_MCOUNT_RECORD
-       /* sechdrs[0].sh_size is always zero */
-       mod->ftrace_callsites = section_objs(hdr, sechdrs, secstrings,
-                                            "__mcount_loc",
-                                            sizeof(*mod->ftrace_callsites),
-                                            &mod->num_ftrace_callsites);
-#endif
 #ifdef CONFIG_MODVERSIONS
        if ((mod->num_syms && !mod->crcs)
            || (mod->num_gpl_syms && !mod->gpl_crcs)
@@ -2441,79 +2461,164 @@ static noinline struct module *load_module(void __user *umod,
            || (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs)
 #endif
                ) {
-               err = try_to_force_load(mod,
-                                       "no versions for exported symbols");
-               if (err)
-                       goto cleanup;
+               return try_to_force_load(mod,
+                                        "no versions for exported symbols");
        }
 #endif
+       return 0;
+}
 
-       /* Now do relocations. */
-       for (i = 1; i < hdr->e_shnum; i++) {
-               const char *strtab = (char *)sechdrs[strindex].sh_addr;
-               unsigned int info = sechdrs[i].sh_info;
+static void flush_module_icache(const struct module *mod)
+{
+       mm_segment_t old_fs;
 
-               /* Not a valid relocation section? */
-               if (info >= hdr->e_shnum)
-                       continue;
+       /* flush the icache in correct context */
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
 
-               /* Don't bother with non-allocated sections */
-               if (!(sechdrs[info].sh_flags & SHF_ALLOC))
-                       continue;
+       /*
+        * Flush the instruction cache, since we've played with text.
+        * Do it before processing of module parameters, so the module
+        * can provide parameter accessor functions of its own.
+        */
+       if (mod->module_init)
+               flush_icache_range((unsigned long)mod->module_init,
+                                  (unsigned long)mod->module_init
+                                  + mod->init_size);
+       flush_icache_range((unsigned long)mod->module_core,
+                          (unsigned long)mod->module_core + mod->core_size);
 
-               if (sechdrs[i].sh_type == SHT_REL)
-                       err = apply_relocate(sechdrs, strtab, symindex, i,mod);
-               else if (sechdrs[i].sh_type == SHT_RELA)
-                       err = apply_relocate_add(sechdrs, strtab, symindex, i,
-                                                mod);
-               if (err < 0)
-                       goto cleanup;
+       set_fs(old_fs);
+}
+
+/* Allocate and load the module: note that size of section 0 is always
+   zero, and we rely on this for optional sections. */
+static noinline struct module *load_module(void __user *umod,
+                                 unsigned long len,
+                                 const char __user *uargs)
+{
+       struct load_info info = { NULL, };
+       struct module *mod;
+       long err;
+       unsigned long symoffs, stroffs, *strmap;
+       void __percpu *percpu;
+       struct _ddebug *debug = NULL;
+       unsigned int num_debug = 0;
+
+       DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
+              umod, len, uargs);
+
+       err = copy_and_check(&info, umod, len);
+       if (err)
+               return ERR_PTR(err);
+
+       mod = setup_load_info(&info);
+       if (IS_ERR(mod)) {
+               err = PTR_ERR(mod);
+               goto free_hdr;
+       }
+
+       err = check_modinfo(mod, info.sechdrs, info.index.info, info.index.vers);
+       if (err)
+               goto free_hdr;
+
+       /* Now copy in args */
+       info.args = strndup_user(uargs, ~0UL >> 1);
+       if (IS_ERR(info.args)) {
+               err = PTR_ERR(info.args);
+               goto free_hdr;
+       }
+
+       strmap = kzalloc(BITS_TO_LONGS(info.sechdrs[info.index.str].sh_size)
+                        * sizeof(long), GFP_KERNEL);
+       if (!strmap) {
+               err = -ENOMEM;
+               goto free_mod;
+       }
+
+       mod->state = MODULE_STATE_COMING;
+
+       /* Allow arches to frob section contents and sizes.  */
+       err = module_frob_arch_sections(info.hdr, info.sechdrs, info.secstrings, mod);
+       if (err < 0)
+               goto free_mod;
+
+       if (info.index.pcpu) {
+               /* We have a special allocation for this section. */
+               err = percpu_modalloc(mod, info.sechdrs[info.index.pcpu].sh_size,
+                                     info.sechdrs[info.index.pcpu].sh_addralign);
+               if (err)
+                       goto free_mod;
+               info.sechdrs[info.index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;
+       }
+       /* Keep this around for failure path. */
+       percpu = mod_percpu(mod);
+
+       /* 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.hdr, info.sechdrs, info.secstrings);
+       symoffs = layout_symtab(mod, info.sechdrs, info.index.sym, info.index.str, info.hdr,
+                               info.secstrings, &stroffs, strmap);
+
+       /* Allocate and move to the final place */
+       mod = move_module(mod, info.hdr, info.sechdrs, info.secstrings, info.index.mod);
+       if (IS_ERR(mod)) {
+               err = PTR_ERR(mod);
+               goto free_percpu;
        }
 
+       /* Now we've moved module, initialize linked lists, etc. */
+       err = module_unload_init(mod);
+       if (err)
+               goto free_init;
+
+       /* Now we've got everything in the final locations, we can
+        * find optional sections. */
+       find_module_sections(mod, info.hdr, info.sechdrs, info.secstrings);
+
+       err = check_module_license_and_versions(mod, info.sechdrs);
+       if (err)
+               goto free_unload;
+
+       /* Set up MODINFO_ATTR fields */
+       setup_modinfo(mod, info.sechdrs, info.index.info);
+
+       /* Fix up syms, so that st_value is a pointer to location. */
+       err = simplify_symbols(info.sechdrs, info.index.sym, info.strtab, info.index.vers, info.index.pcpu,
+                              mod);
+       if (err < 0)
+               goto cleanup;
+
+       err = apply_relocations(mod, info.hdr, info.sechdrs, info.index.sym, info.index.str);
+       if (err < 0)
+               goto cleanup;
+
        /* Set up and sort exception table */
-       mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table",
+       mod->extable = section_objs(info.hdr, info.sechdrs, info.secstrings, "__ex_table",
                                    sizeof(*mod->extable), &mod->num_exentries);
        sort_extable(mod->extable, mod->extable + mod->num_exentries);
 
        /* Finally, copy percpu area over. */
-       percpu_modcopy(mod, (void *)sechdrs[pcpuindex].sh_addr,
-                      sechdrs[pcpuindex].sh_size);
+       percpu_modcopy(mod, (void *)info.sechdrs[info.index.pcpu].sh_addr,
+                      info.sechdrs[info.index.pcpu].sh_size);
 
-       add_kallsyms(mod, sechdrs, hdr->e_shnum, symindex, strindex,
-                    symoffs, stroffs, secstrings, strmap);
+       add_kallsyms(mod, info.sechdrs, info.hdr->e_shnum, info.index.sym, info.index.str,
+                    symoffs, stroffs, info.secstrings, strmap);
        kfree(strmap);
        strmap = NULL;
 
        if (!mod->taints)
-               debug = section_objs(hdr, sechdrs, secstrings, "__verbose",
+               debug = section_objs(info.hdr, info.sechdrs, info.secstrings, "__verbose",
                                     sizeof(*debug), &num_debug);
 
-       err = module_finalize(hdr, sechdrs, mod);
+       err = module_finalize(info.hdr, info.sechdrs, mod);
        if (err < 0)
                goto cleanup;
 
-       /* flush the icache in correct context */
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-
-       /*
-        * Flush the instruction cache, since we've played with text.
-        * Do it before processing of module parameters, so the module
-        * can provide parameter accessor functions of its own.
-        */
-       if (mod->module_init)
-               flush_icache_range((unsigned long)mod->module_init,
-                                  (unsigned long)mod->module_init
-                                  + mod->init_size);
-       flush_icache_range((unsigned long)mod->module_core,
-                          (unsigned long)mod->module_core + mod->core_size);
-
-       set_fs(old_fs);
+       flush_module_icache(mod);
 
-       mod->args = args;
-       if (section_addr(hdr, sechdrs, secstrings, "__obsparm"))
-               printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
-                      mod->name);
+       mod->args = info.args;
 
        /* Now sew it into the lists so we can get lockdep and oops
         * info during argument parsing.  Noone should access us, since
@@ -2547,11 +2652,11 @@ static noinline struct module *load_module(void __user *umod,
        if (err < 0)
                goto unlink;
 
-       add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
-       add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
+       add_sect_attrs(mod, info.hdr->e_shnum, info.secstrings, info.sechdrs);
+       add_notes_attrs(mod, info.hdr->e_shnum, info.secstrings, info.sechdrs);
 
        /* Get rid of temporary copy */
-       vfree(hdr);
+       vfree(info.hdr);
 
        trace_module_load(mod);
 
@@ -2570,28 +2675,20 @@ static noinline struct module *load_module(void __user *umod,
        module_arch_cleanup(mod);
  cleanup:
        free_modinfo(mod);
+ free_unload:
        module_unload_free(mod);
-#if defined(CONFIG_MODULE_UNLOAD)
-       free_percpu(mod->refptr);
  free_init:
-#endif
        module_free(mod, mod->module_init);
- free_core:
        module_free(mod, mod->module_core);
        /* mod will be freed with core. Don't access it beyond this line! */
  free_percpu:
        free_percpu(percpu);
  free_mod:
-       kfree(args);
+       kfree(info.args);
        kfree(strmap);
  free_hdr:
-       vfree(hdr);
+       vfree(info.hdr);
        return ERR_PTR(err);
-
- truncated:
-       printk(KERN_ERR "Module len %lu truncated\n", len);
-       err = -ENOEXEC;
-       goto free_hdr;
 }
 
 /* Call module constructors. */
This page took 0.04568 seconds and 5 git commands to generate.