Merge tag 'modules-for-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 5 Jun 2020 19:31:16 +0000 (12:31 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 5 Jun 2020 19:31:16 +0000 (12:31 -0700)
Pull module updates from Jessica Yu:

 - Harden CONFIG_STRICT_MODULE_RWX by rejecting any module that has
   SHF_WRITE|SHF_EXECINSTR sections

 - Remove and clean up nested #ifdefs, as it makes code hard to read

* tag 'modules-for-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux:
  module: Harden STRICT_MODULE_RWX
  module: break nested ARCH_HAS_STRICT_MODULE_RWX and STRICT_MODULE_RWX #ifdefs

kernel/module.c

index bca993c..ef400c3 100644 (file)
@@ -1946,7 +1946,6 @@ static void mod_sysfs_teardown(struct module *mod)
        mod_sysfs_fini(mod);
 }
 
-#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
 /*
  * LKM RO/NX protection: protect module's text/ro-data
  * from modification and any data from execution.
@@ -1960,6 +1959,14 @@ static void mod_sysfs_teardown(struct module *mod)
  *
  * These values are always page-aligned (as is base)
  */
+
+/*
+ * Since some arches are moving towards PAGE_KERNEL module allocations instead
+ * of PAGE_KERNEL_EXEC, keep frob_text() and module_enable_x() outside of the
+ * CONFIG_STRICT_MODULE_RWX block below because they are needed regardless of
+ * whether we are strict.
+ */
+#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
 static void frob_text(const struct module_layout *layout,
                      int (*set_memory)(unsigned long start, int num_pages))
 {
@@ -1969,6 +1976,15 @@ static void frob_text(const struct module_layout *layout,
                   layout->text_size >> PAGE_SHIFT);
 }
 
+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_x(const struct module *mod) { }
+#endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
+
 #ifdef CONFIG_STRICT_MODULE_RWX
 static void frob_rodata(const struct module_layout *layout,
                        int (*set_memory)(unsigned long start, int num_pages))
@@ -2026,20 +2042,29 @@ static void module_enable_nx(const struct module *mod)
        frob_writable_data(&mod->init_layout, set_memory_nx);
 }
 
+static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
+                                      char *secstrings, struct module *mod)
+{
+       const unsigned long shf_wx = SHF_WRITE|SHF_EXECINSTR;
+       int i;
+
+       for (i = 0; i < hdr->e_shnum; i++) {
+               if ((sechdrs[i].sh_flags & shf_wx) == shf_wx)
+                       return -ENOEXEC;
+       }
+
+       return 0;
+}
+
 #else /* !CONFIG_STRICT_MODULE_RWX */
 static void module_enable_nx(const struct module *mod) { }
 static void module_enable_ro(const struct module *mod, bool after_init) {}
-#endif /*  CONFIG_STRICT_MODULE_RWX */
-static void module_enable_x(const struct module *mod)
+static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
+                                      char *secstrings, struct module *mod)
 {
-       frob_text(&mod->core_layout, set_memory_x);
-       frob_text(&mod->init_layout, set_memory_x);
+       return 0;
 }
-#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 */
-
+#endif /*  CONFIG_STRICT_MODULE_RWX */
 
 #ifdef CONFIG_LIVEPATCH
 /*
@@ -3385,6 +3410,11 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
        if (err < 0)
                return ERR_PTR(err);
 
+       err = module_enforce_rwx_sections(info->hdr, info->sechdrs,
+                                         info->secstrings, info->mod);
+       if (err < 0)
+               return ERR_PTR(err);
+
        /* We will do a special allocation for per-cpu sections later. */
        info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;