Merge tag 'modules-for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 18 Jul 2019 19:06:57 +0000 (12:06 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 18 Jul 2019 19:06:57 +0000 (12:06 -0700)
Pull module updates from Jessica Yu:
 "Summary of modules changes for the 5.3 merge window:

   - Code fixes and cleanups

   - Fix bug where set_memory_x() wasn't being called when rodata=n

   - Fix bug where -EEXIST was being returned for going modules

   - Allow arches to override module_exit_section()"

* tag 'modules-for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux:
  modules: fix compile error if don't have strict module rwx
  ARM: module: recognize unwind exit sections
  module: allow arch overrides for .exit section names
  modules: fix BUG when load module with rodata=n
  kernel/module: Fix mem leak in module_add_modinfo_attrs
  kernel: module: Use struct_size() helper
  kernel/module.c: Only return -EEXIST for modules that have finished loading

arch/arm/kernel/module.c
include/linux/moduleloader.h
kernel/module.c

index b3d439c41c7b8bbd1afee9e3db873d38104a34bc..deef17f34bd277f55b384ca16686111a4b82e93c 100644 (file)
@@ -55,6 +55,13 @@ void *module_alloc(unsigned long size)
 }
 #endif
 
+bool module_exit_section(const char *name)
+{
+       return strstarts(name, ".exit") ||
+               strstarts(name, ".ARM.extab.exit") ||
+               strstarts(name, ".ARM.exidx.exit");
+}
+
 int
 apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
               unsigned int relindex, struct module *module)
index 31013c2effd3d5c7b148d601dff665e8ed10e7b1..5229c18025e97166245b7eb048fc8903d14b07e5 100644 (file)
@@ -29,6 +29,11 @@ void *module_alloc(unsigned long size);
 /* Free memory returned from module_alloc. */
 void module_memfree(void *module_region);
 
+/* Determines if the section name is an exit section (that is only used during
+ * module unloading)
+ */
+bool module_exit_section(const char *name);
+
 /*
  * Apply the given relocation to the (simplified) ELF.  Return -error
  * or 0.
index a2cee14a83f360b8300503f4e5c338d0105c8056..5933395af9a0c18c7ccf1f97543d15050e1550a0 100644 (file)
@@ -1492,8 +1492,7 @@ static void add_sect_attrs(struct module *mod, const struct load_info *info)
        for (i = 0; i < info->hdr->e_shnum; i++)
                if (!sect_empty(&info->sechdrs[i]))
                        nloaded++;
-       size[0] = ALIGN(sizeof(*sect_attrs)
-                       + nloaded * sizeof(sect_attrs->attrs[0]),
+       size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
                        sizeof(sect_attrs->grp.attrs[0]));
        size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]);
        sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
@@ -1697,6 +1696,8 @@ static int add_usage_links(struct module *mod)
        return ret;
 }
 
+static void module_remove_modinfo_attrs(struct module *mod, int end);
+
 static int module_add_modinfo_attrs(struct module *mod)
 {
        struct module_attribute *attr;
@@ -1711,24 +1712,34 @@ static int module_add_modinfo_attrs(struct module *mod)
                return -ENOMEM;
 
        temp_attr = mod->modinfo_attrs;
-       for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
+       for (i = 0; (attr = modinfo_attrs[i]); i++) {
                if (!attr->test || attr->test(mod)) {
                        memcpy(temp_attr, attr, sizeof(*temp_attr));
                        sysfs_attr_init(&temp_attr->attr);
                        error = sysfs_create_file(&mod->mkobj.kobj,
                                        &temp_attr->attr);
+                       if (error)
+                               goto error_out;
                        ++temp_attr;
                }
        }
+
+       return 0;
+
+error_out:
+       if (i > 0)
+               module_remove_modinfo_attrs(mod, --i);
        return error;
 }
 
-static void module_remove_modinfo_attrs(struct module *mod)
+static void module_remove_modinfo_attrs(struct module *mod, int end)
 {
        struct module_attribute *attr;
        int i;
 
        for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
+               if (end >= 0 && i > end)
+                       break;
                /* pick a field to test for end of list */
                if (!attr->attr.name)
                        break;
@@ -1816,7 +1827,7 @@ static int mod_sysfs_setup(struct module *mod,
        return 0;
 
 out_unreg_modinfo_attrs:
-       module_remove_modinfo_attrs(mod);
+       module_remove_modinfo_attrs(mod, -1);
 out_unreg_param:
        module_param_sysfs_remove(mod);
 out_unreg_holders:
@@ -1852,7 +1863,7 @@ static void mod_sysfs_fini(struct module *mod)
 {
 }
 
-static void module_remove_modinfo_attrs(struct module *mod)
+static void module_remove_modinfo_attrs(struct module *mod, int end)
 {
 }
 
@@ -1868,14 +1879,14 @@ static void init_param_lock(struct module *mod)
 static void mod_sysfs_teardown(struct module *mod)
 {
        del_usage_links(mod);
-       module_remove_modinfo_attrs(mod);
+       module_remove_modinfo_attrs(mod, -1);
        module_param_sysfs_remove(mod);
        kobject_put(mod->mkobj.drivers_dir);
        kobject_put(mod->holders_dir);
        mod_sysfs_fini(mod);
 }
 
-#ifdef CONFIG_STRICT_MODULE_RWX
+#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
 /*
  * LKM RO/NX protection: protect module's text/ro-data
  * from modification and any data from execution.
@@ -1898,6 +1909,7 @@ static void frob_text(const struct module_layout *layout,
                   layout->text_size >> PAGE_SHIFT);
 }
 
+#ifdef CONFIG_STRICT_MODULE_RWX
 static void frob_rodata(const struct module_layout *layout,
                        int (*set_memory)(unsigned long start, int num_pages))
 {
@@ -1949,13 +1961,9 @@ void module_enable_ro(const struct module *mod, bool after_init)
        set_vm_flush_reset_perms(mod->core_layout.base);
        set_vm_flush_reset_perms(mod->init_layout.base);
        frob_text(&mod->core_layout, set_memory_ro);
-       frob_text(&mod->core_layout, set_memory_x);
 
        frob_rodata(&mod->core_layout, set_memory_ro);
-
        frob_text(&mod->init_layout, set_memory_ro);
-       frob_text(&mod->init_layout, set_memory_x);
-
        frob_rodata(&mod->init_layout, set_memory_ro);
 
        if (after_init)
@@ -2014,9 +2022,19 @@ void set_all_modules_text_ro(void)
        }
        mutex_unlock(&module_mutex);
 }
-#else
+#else /* !CONFIG_STRICT_MODULE_RWX */
 static void module_enable_nx(const struct module *mod) { }
-#endif
+#endif /*  CONFIG_STRICT_MODULE_RWX */
+static void module_enable_x(const struct module *mod)
+{
+       frob_text(&mod->core_layout, set_memory_x);
+       frob_text(&mod->init_layout, set_memory_x);
+}
+#else /* !CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
+static void module_enable_nx(const struct module *mod) { }
+static void module_enable_x(const struct module *mod) { }
+#endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
+
 
 #ifdef CONFIG_LIVEPATCH
 /*
@@ -2723,6 +2741,11 @@ void * __weak module_alloc(unsigned long size)
        return vmalloc_exec(size);
 }
 
+bool __weak module_exit_section(const char *name)
+{
+       return strstarts(name, ".exit");
+}
+
 #ifdef CONFIG_DEBUG_KMEMLEAK
 static void kmemleak_load_module(const struct module *mod,
                                 const struct load_info *info)
@@ -2912,7 +2935,7 @@ static int rewrite_section_headers(struct load_info *info, int flags)
 
 #ifndef CONFIG_MODULE_UNLOAD
                /* Don't load .exit sections */
-               if (strstarts(info->secstrings+shdr->sh_name, ".exit"))
+               if (module_exit_section(info->secstrings+shdr->sh_name))
                        shdr->sh_flags &= ~(unsigned long)SHF_ALLOC;
 #endif
        }
@@ -3390,8 +3413,7 @@ static bool finished_loading(const char *name)
        sched_annotate_sleep();
        mutex_lock(&module_mutex);
        mod = find_module_all(name, strlen(name), true);
-       ret = !mod || mod->state == MODULE_STATE_LIVE
-               || mod->state == MODULE_STATE_GOING;
+       ret = !mod || mod->state == MODULE_STATE_LIVE;
        mutex_unlock(&module_mutex);
 
        return ret;
@@ -3581,8 +3603,7 @@ again:
        mutex_lock(&module_mutex);
        old = find_module_all(mod->name, strlen(mod->name), true);
        if (old != NULL) {
-               if (old->state == MODULE_STATE_COMING
-                   || old->state == MODULE_STATE_UNFORMED) {
+               if (old->state != MODULE_STATE_LIVE) {
                        /* Wait in case it fails to load. */
                        mutex_unlock(&module_mutex);
                        err = wait_event_interruptible(module_wq,
@@ -3621,6 +3642,7 @@ static int complete_formation(struct module *mod, struct load_info *info)
 
        module_enable_ro(mod, false);
        module_enable_nx(mod);
+       module_enable_x(mod);
 
        /* Mark state as coming so strong_try_module_get() ignores us,
         * but kallsyms etc. can see us. */