Merge tag 'acpi-5.12-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux-2.6-microblaze.git] / kernel / module.c
index 4bf30e4..3047935 100644 (file)
@@ -87,8 +87,7 @@
  * 3) module_addr_min/module_addr_max.
  * (delete and add uses RCU list operations).
  */
-DEFINE_MUTEX(module_mutex);
-EXPORT_SYMBOL_GPL(module_mutex);
+static DEFINE_MUTEX(module_mutex);
 static LIST_HEAD(modules);
 
 /* Work queue for freeing init sections in success case */
@@ -256,11 +255,6 @@ static void mod_update_bounds(struct module *mod)
 struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
 #endif /* CONFIG_KGDB_KDB */
 
-static void module_assert_mutex(void)
-{
-       lockdep_assert_held(&module_mutex);
-}
-
 static void module_assert_mutex_or_preempt(void)
 {
 #ifdef CONFIG_LOCKDEP
@@ -414,19 +408,8 @@ extern const struct kernel_symbol __start___ksymtab[];
 extern const struct kernel_symbol __stop___ksymtab[];
 extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
-extern const struct kernel_symbol __start___ksymtab_gpl_future[];
-extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
 extern const s32 __start___kcrctab[];
 extern const s32 __start___kcrctab_gpl[];
-extern const s32 __start___kcrctab_gpl_future[];
-#ifdef CONFIG_UNUSED_SYMBOLS
-extern const struct kernel_symbol __start___ksymtab_unused[];
-extern const struct kernel_symbol __stop___ksymtab_unused[];
-extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
-extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
-extern const s32 __start___kcrctab_unused[];
-extern const s32 __start___kcrctab_unused_gpl[];
-#endif
 
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
@@ -434,87 +417,14 @@ extern const s32 __start___kcrctab_unused_gpl[];
 #define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
 #endif
 
-static bool each_symbol_in_section(const struct symsearch *arr,
-                                  unsigned int arrsize,
-                                  struct module *owner,
-                                  bool (*fn)(const struct symsearch *syms,
-                                             struct module *owner,
-                                             void *data),
-                                  void *data)
-{
-       unsigned int j;
-
-       for (j = 0; j < arrsize; j++) {
-               if (fn(&arr[j], owner, data))
-                       return true;
-       }
-
-       return false;
-}
-
-/* Returns true as soon as fn returns true, otherwise false. */
-static bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
-                                   struct module *owner,
-                                   void *data),
-                        void *data)
-{
-       struct module *mod;
-       static const struct symsearch arr[] = {
-               { __start___ksymtab, __stop___ksymtab, __start___kcrctab,
-                 NOT_GPL_ONLY, false },
-               { __start___ksymtab_gpl, __stop___ksymtab_gpl,
-                 __start___kcrctab_gpl,
-                 GPL_ONLY, false },
-               { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future,
-                 __start___kcrctab_gpl_future,
-                 WILL_BE_GPL_ONLY, false },
-#ifdef CONFIG_UNUSED_SYMBOLS
-               { __start___ksymtab_unused, __stop___ksymtab_unused,
-                 __start___kcrctab_unused,
-                 NOT_GPL_ONLY, true },
-               { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl,
-                 __start___kcrctab_unused_gpl,
-                 GPL_ONLY, true },
-#endif
-       };
-
-       module_assert_mutex_or_preempt();
-
-       if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data))
-               return true;
-
-       list_for_each_entry_rcu(mod, &modules, list,
-                               lockdep_is_held(&module_mutex)) {
-               struct symsearch arr[] = {
-                       { mod->syms, mod->syms + mod->num_syms, mod->crcs,
-                         NOT_GPL_ONLY, false },
-                       { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
-                         mod->gpl_crcs,
-                         GPL_ONLY, false },
-                       { mod->gpl_future_syms,
-                         mod->gpl_future_syms + mod->num_gpl_future_syms,
-                         mod->gpl_future_crcs,
-                         WILL_BE_GPL_ONLY, false },
-#ifdef CONFIG_UNUSED_SYMBOLS
-                       { mod->unused_syms,
-                         mod->unused_syms + mod->num_unused_syms,
-                         mod->unused_crcs,
-                         NOT_GPL_ONLY, true },
-                       { mod->unused_gpl_syms,
-                         mod->unused_gpl_syms + mod->num_unused_gpl_syms,
-                         mod->unused_gpl_crcs,
-                         GPL_ONLY, true },
-#endif
-               };
-
-               if (mod->state == MODULE_STATE_UNFORMED)
-                       continue;
-
-               if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data))
-                       return true;
-       }
-       return false;
-}
+struct symsearch {
+       const struct kernel_symbol *start, *stop;
+       const s32 *crcs;
+       enum mod_license {
+               NOT_GPL_ONLY,
+               GPL_ONLY,
+       } license;
+};
 
 struct find_symbol_arg {
        /* Input */
@@ -535,28 +445,8 @@ static bool check_exported_symbol(const struct symsearch *syms,
 {
        struct find_symbol_arg *fsa = data;
 
-       if (!fsa->gplok) {
-               if (syms->license == GPL_ONLY)
-                       return false;
-               if (syms->license == WILL_BE_GPL_ONLY && fsa->warn) {
-                       pr_warn("Symbol %s is being used by a non-GPL module, "
-                               "which will not be allowed in the future\n",
-                               fsa->name);
-               }
-       }
-
-#ifdef CONFIG_UNUSED_SYMBOLS
-       if (syms->unused && fsa->warn) {
-               pr_warn("Symbol %s is marked as UNUSED, however this module is "
-                       "using it.\n", fsa->name);
-               pr_warn("This symbol will go away in the future.\n");
-               pr_warn("Please evaluate if this is the right api to use and "
-                       "if it really is, submit a report to the linux kernel "
-                       "mailing list together with submitting your code for "
-                       "inclusion.\n");
-       }
-#endif
-
+       if (!fsa->gplok && syms->license == GPL_ONLY)
+               return false;
        fsa->owner = owner;
        fsa->crc = symversion(syms->crcs, symnum);
        fsa->sym = &syms->start[symnum];
@@ -619,31 +509,44 @@ static bool find_exported_symbol_in_section(const struct symsearch *syms,
  * Find an exported symbol and return it, along with, (optional) crc and
  * (optional) module which owns it.  Needs preempt disabled or module_mutex.
  */
-static const struct kernel_symbol *find_symbol(const char *name,
-                                       struct module **owner,
-                                       const s32 **crc,
-                                       enum mod_license *license,
-                                       bool gplok,
-                                       bool warn)
-{
-       struct find_symbol_arg fsa;
-
-       fsa.name = name;
-       fsa.gplok = gplok;
-       fsa.warn = warn;
-
-       if (each_symbol_section(find_exported_symbol_in_section, &fsa)) {
-               if (owner)
-                       *owner = fsa.owner;
-               if (crc)
-                       *crc = fsa.crc;
-               if (license)
-                       *license = fsa.license;
-               return fsa.sym;
+static bool find_symbol(struct find_symbol_arg *fsa)
+{
+       static const struct symsearch arr[] = {
+               { __start___ksymtab, __stop___ksymtab, __start___kcrctab,
+                 NOT_GPL_ONLY },
+               { __start___ksymtab_gpl, __stop___ksymtab_gpl,
+                 __start___kcrctab_gpl,
+                 GPL_ONLY },
+       };
+       struct module *mod;
+       unsigned int i;
+
+       module_assert_mutex_or_preempt();
+
+       for (i = 0; i < ARRAY_SIZE(arr); i++)
+               if (find_exported_symbol_in_section(&arr[i], NULL, fsa))
+                       return true;
+
+       list_for_each_entry_rcu(mod, &modules, list,
+                               lockdep_is_held(&module_mutex)) {
+               struct symsearch arr[] = {
+                       { mod->syms, mod->syms + mod->num_syms, mod->crcs,
+                         NOT_GPL_ONLY },
+                       { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
+                         mod->gpl_crcs,
+                         GPL_ONLY },
+               };
+
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
+
+               for (i = 0; i < ARRAY_SIZE(arr); i++)
+                       if (find_exported_symbol_in_section(&arr[i], mod, fsa))
+                               return true;
        }
 
-       pr_debug("Failed to find symbol %s\n", name);
-       return NULL;
+       pr_debug("Failed to find symbol %s\n", fsa->name);
+       return false;
 }
 
 /*
@@ -669,10 +572,8 @@ static struct module *find_module_all(const char *name, size_t len,
 
 struct module *find_module(const char *name)
 {
-       module_assert_mutex();
        return find_module_all(name, strlen(name), false);
 }
-EXPORT_SYMBOL_GPL(find_module);
 
 #ifdef CONFIG_SMP
 
@@ -1107,12 +1008,15 @@ static inline void print_unload_info(struct seq_file *m, struct module *mod)
 
 void __symbol_put(const char *symbol)
 {
-       struct module *owner;
+       struct find_symbol_arg fsa = {
+               .name   = symbol,
+               .gplok  = true,
+       };
 
        preempt_disable();
-       if (!find_symbol(symbol, &owner, NULL, NULL, true, false))
+       if (!find_symbol(&fsa))
                BUG();
-       module_put(owner);
+       module_put(fsa.owner);
        preempt_enable();
 }
 EXPORT_SYMBOL(__symbol_put);
@@ -1381,19 +1285,22 @@ bad_version:
 static inline int check_modstruct_version(const struct load_info *info,
                                          struct module *mod)
 {
-       const s32 *crc;
+       struct find_symbol_arg fsa = {
+               .name   = "module_layout",
+               .gplok  = true,
+       };
 
        /*
         * Since this should be found in kernel (which can't be removed), no
         * locking is necessary -- use preempt_disable() to placate lockdep.
         */
        preempt_disable();
-       if (!find_symbol("module_layout", NULL, &crc, NULL, true, false)) {
+       if (!find_symbol(&fsa)) {
                preempt_enable();
                BUG();
        }
        preempt_enable();
-       return check_version(info, "module_layout", mod, crc);
+       return check_version(info, "module_layout", mod, fsa.crc);
 }
 
 /* First part is kernel version, which we ignore if module has crcs. */
@@ -1487,10 +1394,11 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
                                                  const char *name,
                                                  char ownername[])
 {
-       struct module *owner;
-       const struct kernel_symbol *sym;
-       const s32 *crc;
-       enum mod_license license;
+       struct find_symbol_arg fsa = {
+               .name   = name,
+               .gplok  = !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)),
+               .warn   = true,
+       };
        int err;
 
        /*
@@ -1500,42 +1408,40 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
         */
        sched_annotate_sleep();
        mutex_lock(&module_mutex);
-       sym = find_symbol(name, &owner, &crc, &license,
-                         !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true);
-       if (!sym)
+       if (!find_symbol(&fsa))
                goto unlock;
 
-       if (license == GPL_ONLY)
+       if (fsa.license == GPL_ONLY)
                mod->using_gplonly_symbols = true;
 
-       if (!inherit_taint(mod, owner)) {
-               sym = NULL;
+       if (!inherit_taint(mod, fsa.owner)) {
+               fsa.sym = NULL;
                goto getname;
        }
 
-       if (!check_version(info, name, mod, crc)) {
-               sym = ERR_PTR(-EINVAL);
+       if (!check_version(info, name, mod, fsa.crc)) {
+               fsa.sym = ERR_PTR(-EINVAL);
                goto getname;
        }
 
-       err = verify_namespace_is_imported(info, sym, mod);
+       err = verify_namespace_is_imported(info, fsa.sym, mod);
        if (err) {
-               sym = ERR_PTR(err);
+               fsa.sym = ERR_PTR(err);
                goto getname;
        }
 
-       err = ref_module(mod, owner);
+       err = ref_module(mod, fsa.owner);
        if (err) {
-               sym = ERR_PTR(err);
+               fsa.sym = ERR_PTR(err);
                goto getname;
        }
 
 getname:
        /* We must make copy under the lock if we failed to get ref. */
-       strncpy(ownername, module_name(owner), MODULE_NAME_LEN);
+       strncpy(ownername, module_name(fsa.owner), MODULE_NAME_LEN);
 unlock:
        mutex_unlock(&module_mutex);
-       return sym;
+       return fsa.sym;
 }
 
 static const struct kernel_symbol *
@@ -2296,16 +2202,19 @@ static void free_module(struct module *mod)
 
 void *__symbol_get(const char *symbol)
 {
-       struct module *owner;
-       const struct kernel_symbol *sym;
+       struct find_symbol_arg fsa = {
+               .name   = symbol,
+               .gplok  = true,
+               .warn   = true,
+       };
 
        preempt_disable();
-       sym = find_symbol(symbol, &owner, NULL, NULL, true, true);
-       if (sym && strong_try_module_get(owner))
-               sym = NULL;
+       if (!find_symbol(&fsa) || strong_try_module_get(fsa.owner)) {
+               preempt_enable();
+               return NULL;
+       }
        preempt_enable();
-
-       return sym ? (void *)kernel_symbol_value(sym) : NULL;
+       return (void *)kernel_symbol_value(fsa.sym);
 }
 EXPORT_SYMBOL_GPL(__symbol_get);
 
@@ -2318,7 +2227,6 @@ EXPORT_SYMBOL_GPL(__symbol_get);
 static int verify_exported_symbols(struct module *mod)
 {
        unsigned int i;
-       struct module *owner;
        const struct kernel_symbol *s;
        struct {
                const struct kernel_symbol *sym;
@@ -2326,21 +2234,19 @@ static int verify_exported_symbols(struct module *mod)
        } arr[] = {
                { mod->syms, mod->num_syms },
                { mod->gpl_syms, mod->num_gpl_syms },
-               { mod->gpl_future_syms, mod->num_gpl_future_syms },
-#ifdef CONFIG_UNUSED_SYMBOLS
-               { mod->unused_syms, mod->num_unused_syms },
-               { mod->unused_gpl_syms, mod->num_unused_gpl_syms },
-#endif
        };
 
        for (i = 0; i < ARRAY_SIZE(arr); i++) {
                for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
-                       if (find_symbol(kernel_symbol_name(s), &owner, NULL,
-                                       NULL, true, false)) {
+                       struct find_symbol_arg fsa = {
+                               .name   = kernel_symbol_name(s),
+                               .gplok  = true,
+                       };
+                       if (find_symbol(&fsa)) {
                                pr_err("%s: exports duplicate symbol %s"
                                       " (owned by %s)\n",
                                       mod->name, kernel_symbol_name(s),
-                                      module_name(owner));
+                                      module_name(fsa.owner));
                                return -ENOEXEC;
                        }
                }
@@ -2348,6 +2254,21 @@ static int verify_exported_symbols(struct module *mod)
        return 0;
 }
 
+static bool ignore_undef_symbol(Elf_Half emachine, const char *name)
+{
+       /*
+        * On x86, PIC code and Clang non-PIC code may have call foo@PLT. GNU as
+        * before 2.37 produces an unreferenced _GLOBAL_OFFSET_TABLE_ on x86-64.
+        * i386 has a similar problem but may not deserve a fix.
+        *
+        * If we ever have to ignore many symbols, consider refactoring the code to
+        * only warn if referenced by a relocation.
+        */
+       if (emachine == EM_386 || emachine == EM_X86_64)
+               return !strcmp(name, "_GLOBAL_OFFSET_TABLE_");
+       return false;
+}
+
 /* Change all symbols so that st_value encodes the pointer directly. */
 static int simplify_symbols(struct module *mod, const struct load_info *info)
 {
@@ -2395,8 +2316,10 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
                                break;
                        }
 
-                       /* Ok if weak.  */
-                       if (!ksym && ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
+                       /* Ok if weak or ignored.  */
+                       if (!ksym &&
+                           (ELF_ST_BIND(sym[i].st_info) == STB_WEAK ||
+                            ignore_undef_symbol(info->hdr->e_machine, name)))
                                break;
 
                        ret = PTR_ERR(ksym) ?: -ENOENT;
@@ -2964,7 +2887,7 @@ static int module_sig_check(struct load_info *info, int flags)
        }
 
        if (is_module_sig_enforced()) {
-               pr_notice("%s: loading of %s is rejected\n", info->name, reason);
+               pr_notice("Loading of %s is rejected\n", reason);
                return -EKEYREJECTED;
        }
 
@@ -2977,9 +2900,33 @@ static int module_sig_check(struct load_info *info, int flags)
 }
 #endif /* !CONFIG_MODULE_SIG */
 
-/* Sanity checks against invalid binaries, wrong arch, weird elf version. */
-static int elf_header_check(struct load_info *info)
+static int validate_section_offset(struct load_info *info, Elf_Shdr *shdr)
+{
+       unsigned long secend;
+
+       /*
+        * Check for both overflow and offset/size being
+        * too large.
+        */
+       secend = shdr->sh_offset + shdr->sh_size;
+       if (secend < shdr->sh_offset || secend > info->len)
+               return -ENOEXEC;
+
+       return 0;
+}
+
+/*
+ * Sanity checks against invalid binaries, wrong arch, weird elf version.
+ *
+ * Also do basic validity checks against section offsets and sizes, the
+ * section name string table, and the indices used for it (sh_name).
+ */
+static int elf_validity_check(struct load_info *info)
 {
+       unsigned int i;
+       Elf_Shdr *shdr, *strhdr;
+       int err;
+
        if (info->len < sizeof(*(info->hdr)))
                return -ENOEXEC;
 
@@ -2989,11 +2936,78 @@ static int elf_header_check(struct load_info *info)
            || info->hdr->e_shentsize != sizeof(Elf_Shdr))
                return -ENOEXEC;
 
+       /*
+        * e_shnum is 16 bits, and sizeof(Elf_Shdr) is
+        * known and small. So e_shnum * sizeof(Elf_Shdr)
+        * will not overflow unsigned long on any platform.
+        */
        if (info->hdr->e_shoff >= info->len
            || (info->hdr->e_shnum * sizeof(Elf_Shdr) >
                info->len - info->hdr->e_shoff))
                return -ENOEXEC;
 
+       info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
+
+       /*
+        * Verify if the section name table index is valid.
+        */
+       if (info->hdr->e_shstrndx == SHN_UNDEF
+           || info->hdr->e_shstrndx >= info->hdr->e_shnum)
+               return -ENOEXEC;
+
+       strhdr = &info->sechdrs[info->hdr->e_shstrndx];
+       err = validate_section_offset(info, strhdr);
+       if (err < 0)
+               return err;
+
+       /*
+        * The section name table must be NUL-terminated, as required
+        * by the spec. This makes strcmp and pr_* calls that access
+        * strings in the section safe.
+        */
+       info->secstrings = (void *)info->hdr + strhdr->sh_offset;
+       if (info->secstrings[strhdr->sh_size - 1] != '\0')
+               return -ENOEXEC;
+
+       /*
+        * The code assumes that section 0 has a length of zero and
+        * an addr of zero, so check for it.
+        */
+       if (info->sechdrs[0].sh_type != SHT_NULL
+           || info->sechdrs[0].sh_size != 0
+           || info->sechdrs[0].sh_addr != 0)
+               return -ENOEXEC;
+
+       for (i = 1; i < info->hdr->e_shnum; i++) {
+               shdr = &info->sechdrs[i];
+               switch (shdr->sh_type) {
+               case SHT_NULL:
+               case SHT_NOBITS:
+                       continue;
+               case SHT_SYMTAB:
+                       if (shdr->sh_link == SHN_UNDEF
+                           || shdr->sh_link >= info->hdr->e_shnum)
+                               return -ENOEXEC;
+                       fallthrough;
+               default:
+                       err = validate_section_offset(info, shdr);
+                       if (err < 0) {
+                               pr_err("Invalid ELF section in module (section %u type %u)\n",
+                                       i, shdr->sh_type);
+                               return err;
+                       }
+
+                       if (shdr->sh_flags & SHF_ALLOC) {
+                               if (shdr->sh_name >= strhdr->sh_size) {
+                                       pr_err("Invalid ELF section name in module (section %u type %u)\n",
+                                              i, shdr->sh_type);
+                                       return -ENOEXEC;
+                               }
+                       }
+                       break;
+               }
+       }
+
        return 0;
 }
 
@@ -3095,11 +3109,6 @@ static int rewrite_section_headers(struct load_info *info, int flags)
 
        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) {
-                       pr_err("Module len %lu truncated\n", info->len);
-                       return -ENOEXEC;
-               }
 
                /*
                 * Mark all sections sh_addr with their address in the
@@ -3133,11 +3142,6 @@ static int setup_load_info(struct load_info *info, int flags)
 {
        unsigned int i;
 
-       /* 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;
-
        /* 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)
@@ -3241,22 +3245,7 @@ static int find_module_sections(struct module *mod, struct load_info *info)
                                     sizeof(*mod->gpl_syms),
                                     &mod->num_gpl_syms);
        mod->gpl_crcs = section_addr(info, "__kcrctab_gpl");
-       mod->gpl_future_syms = section_objs(info,
-                                           "__ksymtab_gpl_future",
-                                           sizeof(*mod->gpl_future_syms),
-                                           &mod->num_gpl_future_syms);
-       mod->gpl_future_crcs = section_addr(info, "__kcrctab_gpl_future");
-
-#ifdef CONFIG_UNUSED_SYMBOLS
-       mod->unused_syms = section_objs(info, "__ksymtab_unused",
-                                       sizeof(*mod->unused_syms),
-                                       &mod->num_unused_syms);
-       mod->unused_crcs = section_addr(info, "__kcrctab_unused");
-       mod->unused_gpl_syms = section_objs(info, "__ksymtab_unused_gpl",
-                                           sizeof(*mod->unused_gpl_syms),
-                                           &mod->num_unused_gpl_syms);
-       mod->unused_gpl_crcs = section_addr(info, "__kcrctab_unused_gpl");
-#endif
+
 #ifdef CONFIG_CONSTRUCTORS
        mod->ctors = section_objs(info, ".ctors",
                                  sizeof(*mod->ctors), &mod->num_ctors);
@@ -3437,14 +3426,8 @@ static int check_module_license_and_versions(struct module *mod)
                pr_warn("%s: module license taints kernel.\n", mod->name);
 
 #ifdef CONFIG_MODVERSIONS
-       if ((mod->num_syms && !mod->crcs)
-           || (mod->num_gpl_syms && !mod->gpl_crcs)
-           || (mod->num_gpl_future_syms && !mod->gpl_future_crcs)
-#ifdef CONFIG_UNUSED_SYMBOLS
-           || (mod->num_unused_syms && !mod->unused_crcs)
-           || (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs)
-#endif
-               ) {
+       if ((mod->num_syms && !mod->crcs) ||
+           (mod->num_gpl_syms && !mod->gpl_crcs)) {
                return try_to_force_load(mod,
                                         "no versions for exported symbols");
        }
@@ -3894,26 +3877,50 @@ static int load_module(struct load_info *info, const char __user *uargs,
        long err = 0;
        char *after_dashes;
 
-       err = elf_header_check(info);
+       /*
+        * Do the signature check (if any) first. All that
+        * the signature check needs is info->len, it does
+        * not need any of the section info. That can be
+        * set up later. This will minimize the chances
+        * of a corrupt module causing problems before
+        * we even get to the signature check.
+        *
+        * The check will also adjust info->len by stripping
+        * off the sig length at the end of the module, making
+        * checks against info->len more correct.
+        */
+       err = module_sig_check(info, flags);
+       if (err)
+               goto free_copy;
+
+       /*
+        * Do basic sanity checks against the ELF header and
+        * sections.
+        */
+       err = elf_validity_check(info);
        if (err) {
-               pr_err("Module has invalid ELF header\n");
+               pr_err("Module has invalid ELF structures\n");
                goto free_copy;
        }
 
+       /*
+        * Everything checks out, so set up the section info
+        * in the info structure.
+        */
        err = setup_load_info(info, flags);
        if (err)
                goto free_copy;
 
+       /*
+        * Now that we know we have the correct module name, check
+        * if it's blacklisted.
+        */
        if (blacklisted(info->name)) {
                err = -EPERM;
                pr_err("Module %s is blacklisted\n", info->name);
                goto free_copy;
        }
 
-       err = module_sig_check(info, flags);
-       if (err)
-               goto free_copy;
-
        err = rewrite_section_headers(info, flags);
        if (err)
                goto free_copy;
@@ -4374,16 +4381,16 @@ unsigned long module_kallsyms_lookup_name(const char *name)
        return ret;
 }
 
+#ifdef CONFIG_LIVEPATCH
 int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
                                             struct module *, unsigned long),
                                   void *data)
 {
        struct module *mod;
        unsigned int i;
-       int ret;
-
-       module_assert_mutex();
+       int ret = 0;
 
+       mutex_lock(&module_mutex);
        list_for_each_entry(mod, &modules, list) {
                /* We hold module_mutex: no need for rcu_dereference_sched */
                struct mod_kallsyms *kallsyms = mod->kallsyms;
@@ -4399,11 +4406,13 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
                        ret = fn(data, kallsyms_symbol_name(kallsyms, i),
                                 mod, kallsyms_symbol_value(sym));
                        if (ret != 0)
-                               return ret;
+                               break;
                }
        }
-       return 0;
+       mutex_unlock(&module_mutex);
+       return ret;
 }
+#endif /* CONFIG_LIVEPATCH */
 #endif /* CONFIG_KALLSYMS */
 
 /* Maximum number of characters written by module_flags() */