Merge tag 'modules-for-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Jul 2017 00:22:01 +0000 (17:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Jul 2017 00:22:01 +0000 (17:22 -0700)
Pull modules updates from Jessica Yu:
 "Summary of modules changes for the 4.13 merge window:

   - Minor code cleanups

   - Avoid accessing mod struct prior to checking module struct version,
     from Kees

   - Fix racy atomic inc/dec logic of kmod_concurrent_max in kmod, from
     Luis"

* tag 'modules-for-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux:
  module: make the modinfo name const
  kmod: reduce atomic operations on kmod_concurrent and simplify
  module: use list_for_each_entry_rcu() on find_module_all()
  kernel/module.c: suppress warning about unused nowarn variable
  module: Add module name to modinfo
  module: Pass struct load_info into symbol checks

kernel/kmod.c
kernel/module.c
scripts/mod/modpost.c

index 563f97e2be3618574f523e2e96442c80ae7bc882..ff68198fe83bcb6b9edfcc9999ff57288e322de7 100644 (file)
@@ -45,8 +45,6 @@
 
 #include <trace/events/module.h>
 
-extern int max_threads;
-
 #define CAP_BSET       (void *)1
 #define CAP_PI         (void *)2
 
@@ -56,6 +54,20 @@ static DEFINE_SPINLOCK(umh_sysctl_lock);
 static DECLARE_RWSEM(umhelper_sem);
 
 #ifdef CONFIG_MODULES
+/*
+ * Assuming:
+ *
+ * threads = div64_u64((u64) totalram_pages * (u64) PAGE_SIZE,
+ *                    (u64) THREAD_SIZE * 8UL);
+ *
+ * If you need less than 50 threads would mean we're dealing with systems
+ * smaller than 3200 pages. This assuems you are capable of having ~13M memory,
+ * and this would only be an be an upper limit, after which the OOM killer
+ * would take effect. Systems like these are very unlikely if modules are
+ * enabled.
+ */
+#define MAX_KMOD_CONCURRENT 50
+static atomic_t kmod_concurrent_max = ATOMIC_INIT(MAX_KMOD_CONCURRENT);
 
 /*
        modprobe_path is set via /proc/sys.
@@ -127,10 +139,7 @@ int __request_module(bool wait, const char *fmt, ...)
 {
        va_list args;
        char module_name[MODULE_NAME_LEN];
-       unsigned int max_modprobes;
        int ret;
-       static atomic_t kmod_concurrent = ATOMIC_INIT(0);
-#define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */
        static int kmod_loop_msg;
 
        /*
@@ -154,21 +163,7 @@ int __request_module(bool wait, const char *fmt, ...)
        if (ret)
                return ret;
 
-       /* If modprobe needs a service that is in a module, we get a recursive
-        * loop.  Limit the number of running kmod threads to max_threads/2 or
-        * MAX_KMOD_CONCURRENT, whichever is the smaller.  A cleaner method
-        * would be to run the parents of this process, counting how many times
-        * kmod was invoked.  That would mean accessing the internals of the
-        * process tables to get the command line, proc_pid_cmdline is static
-        * and it is not worth changing the proc code just to handle this case. 
-        * KAO.
-        *
-        * "trace the ppid" is simple, but will fail if someone's
-        * parent exits.  I think this is as good as it gets. --RR
-        */
-       max_modprobes = min(max_threads/2, MAX_KMOD_CONCURRENT);
-       atomic_inc(&kmod_concurrent);
-       if (atomic_read(&kmod_concurrent) > max_modprobes) {
+       if (atomic_dec_if_positive(&kmod_concurrent_max) < 0) {
                /* We may be blaming an innocent here, but unlikely */
                if (kmod_loop_msg < 5) {
                        printk(KERN_ERR
@@ -176,7 +171,6 @@ int __request_module(bool wait, const char *fmt, ...)
                               module_name);
                        kmod_loop_msg++;
                }
-               atomic_dec(&kmod_concurrent);
                return -ENOMEM;
        }
 
@@ -184,10 +178,12 @@ int __request_module(bool wait, const char *fmt, ...)
 
        ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
 
-       atomic_dec(&kmod_concurrent);
+       atomic_inc(&kmod_concurrent_max);
+
        return ret;
 }
 EXPORT_SYMBOL(__request_module);
+
 #endif /* CONFIG_MODULES */
 
 static void call_usermodehelper_freeinfo(struct subprocess_info *info)
index b0f92a3651403861530ee487ea7c6b987fe010ab..40f983cbea81d1e3711955dfb2409659d89fd317 100644 (file)
@@ -300,6 +300,7 @@ int unregister_module_notifier(struct notifier_block *nb)
 EXPORT_SYMBOL(unregister_module_notifier);
 
 struct load_info {
+       const char *name;
        Elf_Ehdr *hdr;
        unsigned long len;
        Elf_Shdr *sechdrs;
@@ -600,7 +601,7 @@ static struct module *find_module_all(const char *name, size_t len,
 
        module_assert_mutex_or_preempt();
 
-       list_for_each_entry(mod, &modules, list) {
+       list_for_each_entry_rcu(mod, &modules, list) {
                if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
                        continue;
                if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
@@ -1273,12 +1274,13 @@ static u32 resolve_rel_crc(const s32 *crc)
        return *(u32 *)((void *)crc + *crc);
 }
 
-static int check_version(Elf_Shdr *sechdrs,
-                        unsigned int versindex,
+static int check_version(const struct load_info *info,
                         const char *symname,
                         struct module *mod,
                         const s32 *crc)
 {
+       Elf_Shdr *sechdrs = info->sechdrs;
+       unsigned int versindex = info->index.vers;
        unsigned int i, num_versions;
        struct modversion_info *versions;
 
@@ -1312,17 +1314,16 @@ static int check_version(Elf_Shdr *sechdrs,
        }
 
        /* Broken toolchain. Warn once, then let it go.. */
-       pr_warn_once("%s: no symbol version for %s\n", mod->name, symname);
+       pr_warn_once("%s: no symbol version for %s\n", info->name, symname);
        return 1;
 
 bad_version:
        pr_warn("%s: disagrees about version of symbol %s\n",
-              mod->name, symname);
+              info->name, symname);
        return 0;
 }
 
-static inline int check_modstruct_version(Elf_Shdr *sechdrs,
-                                         unsigned int versindex,
+static inline int check_modstruct_version(const struct load_info *info,
                                          struct module *mod)
 {
        const s32 *crc;
@@ -1338,8 +1339,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
                BUG();
        }
        preempt_enable();
-       return check_version(sechdrs, versindex,
-                            VMLINUX_SYMBOL_STR(module_layout), mod, crc);
+       return check_version(info, VMLINUX_SYMBOL_STR(module_layout),
+                            mod, crc);
 }
 
 /* First part is kernel version, which we ignore if module has crcs. */
@@ -1353,8 +1354,7 @@ static inline int same_magic(const char *amagic, const char *bmagic,
        return strcmp(amagic, bmagic) == 0;
 }
 #else
-static inline int check_version(Elf_Shdr *sechdrs,
-                               unsigned int versindex,
+static inline int check_version(const struct load_info *info,
                                const char *symname,
                                struct module *mod,
                                const s32 *crc)
@@ -1362,8 +1362,7 @@ static inline int check_version(Elf_Shdr *sechdrs,
        return 1;
 }
 
-static inline int check_modstruct_version(Elf_Shdr *sechdrs,
-                                         unsigned int versindex,
+static inline int check_modstruct_version(const struct load_info *info,
                                          struct module *mod)
 {
        return 1;
@@ -1399,7 +1398,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
        if (!sym)
                goto unlock;
 
-       if (!check_version(info->sechdrs, info->index.vers, name, mod, crc)) {
+       if (!check_version(info, name, mod, crc)) {
                sym = ERR_PTR(-EINVAL);
                goto getname;
        }
@@ -1662,31 +1661,36 @@ static inline void remove_notes_attrs(struct module *mod)
 }
 #endif /* CONFIG_KALLSYMS */
 
-static void add_usage_links(struct module *mod)
+static void del_usage_links(struct module *mod)
 {
 #ifdef CONFIG_MODULE_UNLOAD
        struct module_use *use;
-       int nowarn;
 
        mutex_lock(&module_mutex);
-       list_for_each_entry(use, &mod->target_list, target_list) {
-               nowarn = sysfs_create_link(use->target->holders_dir,
-                                          &mod->mkobj.kobj, mod->name);
-       }
+       list_for_each_entry(use, &mod->target_list, target_list)
+               sysfs_remove_link(use->target->holders_dir, mod->name);
        mutex_unlock(&module_mutex);
 #endif
 }
 
-static void del_usage_links(struct module *mod)
+static int add_usage_links(struct module *mod)
 {
+       int ret = 0;
 #ifdef CONFIG_MODULE_UNLOAD
        struct module_use *use;
 
        mutex_lock(&module_mutex);
-       list_for_each_entry(use, &mod->target_list, target_list)
-               sysfs_remove_link(use->target->holders_dir, mod->name);
+       list_for_each_entry(use, &mod->target_list, target_list) {
+               ret = sysfs_create_link(use->target->holders_dir,
+                                       &mod->mkobj.kobj, mod->name);
+               if (ret)
+                       break;
+       }
        mutex_unlock(&module_mutex);
+       if (ret)
+               del_usage_links(mod);
 #endif
+       return ret;
 }
 
 static int module_add_modinfo_attrs(struct module *mod)
@@ -1797,13 +1801,18 @@ static int mod_sysfs_setup(struct module *mod,
        if (err)
                goto out_unreg_param;
 
-       add_usage_links(mod);
+       err = add_usage_links(mod);
+       if (err)
+               goto out_unreg_modinfo_attrs;
+
        add_sect_attrs(mod, info);
        add_notes_attrs(mod, info);
 
        kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);
        return 0;
 
+out_unreg_modinfo_attrs:
+       module_remove_modinfo_attrs(mod);
 out_unreg_param:
        module_param_sysfs_remove(mod);
 out_unreg_holders:
@@ -2910,9 +2919,15 @@ static int rewrite_section_headers(struct load_info *info, int flags)
                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;
-       info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
+
        return 0;
 }
 
@@ -2952,21 +2967,29 @@ static struct module *setup_load_info(struct load_info *info, int flags)
 
        info->index.mod = find_sec(info, ".gnu.linkonce.this_module");
        if (!info->index.mod) {
-               pr_warn("No module found in object\n");
+               pr_warn("%s: No module found in object\n",
+                       info->name ?: "(missing .modinfo name field)");
                return ERR_PTR(-ENOEXEC);
        }
        /* This is temporary: point mod into copy of data. */
        mod = (void *)info->sechdrs[info->index.mod].sh_addr;
 
+       /*
+        * If we didn't load the .modinfo 'name' field, fall back to
+        * on-disk struct mod 'name' field.
+        */
+       if (!info->name)
+               info->name = mod->name;
+
        if (info->index.sym == 0) {
-               pr_warn("%s: module has no symbols (stripped?)\n", mod->name);
+               pr_warn("%s: module has no symbols (stripped?)\n", info->name);
                return ERR_PTR(-ENOEXEC);
        }
 
        info->index.pcpu = find_pcpusec(info);
 
        /* Check module struct version now, before we try to use module. */
-       if (!check_modstruct_version(info->sechdrs, info->index.vers, mod))
+       if (!check_modstruct_version(info, mod))
                return ERR_PTR(-ENOEXEC);
 
        return mod;
@@ -2987,7 +3010,7 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
                        return err;
        } else if (!same_magic(modmagic, vermagic, info->index.vers)) {
                pr_err("%s: version magic '%s' should be '%s'\n",
-                      mod->name, modmagic, vermagic);
+                      info->name, modmagic, vermagic);
                return -ENOEXEC;
        }
 
@@ -3237,7 +3260,7 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr,
 
 /* module_blacklist is a comma-separated list of module names */
 static char *module_blacklist;
-static bool blacklisted(char *module_name)
+static bool blacklisted(const char *module_name)
 {
        const char *p;
        size_t len;
@@ -3267,7 +3290,7 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
        if (IS_ERR(mod))
                return mod;
 
-       if (blacklisted(mod->name))
+       if (blacklisted(info->name))
                return ERR_PTR(-EPERM);
 
        err = check_modinfo(mod, info, flags);
index 30d752a4a6a600a05efbea75039c6072552455e0..48397feb08fba88270e4e60c16f77f0ec2f483b4 100644 (file)
@@ -2126,6 +2126,7 @@ static void add_header(struct buffer *b, struct module *mod)
        buf_printf(b, "#include <linux/compiler.h>\n");
        buf_printf(b, "\n");
        buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
+       buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
        buf_printf(b, "\n");
        buf_printf(b, "__visible struct module __this_module\n");
        buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");