module: Move strict rwx support to a separate file
authorAaron Tomlin <atomlin@redhat.com>
Tue, 22 Mar 2022 14:03:36 +0000 (14:03 +0000)
committerLuis Chamberlain <mcgrof@kernel.org>
Tue, 5 Apr 2022 15:43:04 +0000 (08:43 -0700)
No functional change.

This patch migrates code that makes module text
and rodata memory read-only and non-text memory
non-executable from core module code into
kernel/module/strict_rwx.c.

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
kernel/module/Makefile
kernel/module/internal.h
kernel/module/main.c
kernel/module/strict_rwx.c [new file with mode: 0644]

index 88774e3..d313c84 100644 (file)
@@ -12,3 +12,4 @@ obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o
 obj-$(CONFIG_MODULE_SIG) += signing.o
 obj-$(CONFIG_LIVEPATCH) += livepatch.o
 obj-$(CONFIG_MODULES_TREE_LOOKUP) += tree_lookup.o
+obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
index f1682e3..a6895bb 100644 (file)
 /* Maximum number of characters written by module_flags() */
 #define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4)
 
+/*
+ * Modules' sections will be aligned on page boundaries
+ * to ensure complete separation of code and data, but
+ * only when CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
+ */
+#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
+# define debug_align(X) PAGE_ALIGN(X)
+#else
+# define debug_align(X) (X)
+#endif
+
 extern struct mutex module_mutex;
 extern struct list_head modules;
 
@@ -126,3 +137,24 @@ static inline struct module *mod_find(unsigned long addr)
        return NULL;
 }
 #endif /* CONFIG_MODULES_TREE_LOOKUP */
+
+#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
+void frob_text(const struct module_layout *layout, int (*set_memory)(unsigned long start,
+                                                                    int num_pages));
+#endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
+
+#ifdef CONFIG_STRICT_MODULE_RWX
+void module_enable_ro(const struct module *mod, bool after_init);
+void module_enable_nx(const struct module *mod);
+int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
+                               char *secstrings, struct module *mod);
+
+#else /* !CONFIG_STRICT_MODULE_RWX */
+static inline void module_enable_nx(const struct module *mod) { }
+static inline void module_enable_ro(const struct module *mod, bool after_init) {}
+static inline int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
+                                      char *secstrings, struct module *mod)
+{
+       return 0;
+}
+#endif /* CONFIG_STRICT_MODULE_RWX */
index 0d0fdd8..d55a2a8 100644 (file)
 #include <trace/events/module.h>
 
 /*
- * Modules' sections will be aligned on page boundaries
- * to ensure complete separation of code and data, but
- * only when CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
- */
-#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
-# define debug_align(X) ALIGN(X, PAGE_SIZE)
-#else
-# define debug_align(X) (X)
-#endif
-
-/*
  * Mutex protects:
  * 1) List of modules (also safely readable with preempt_disable),
  * 2) module_use links,
@@ -1819,8 +1808,8 @@ static void mod_sysfs_teardown(struct module *mod)
  * 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))
+void frob_text(const struct module_layout *layout,
+              int (*set_memory)(unsigned long start, int num_pages))
 {
        BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
        BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
@@ -1837,90 +1826,6 @@ static void module_enable_x(const struct module *mod)
 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))
-{
-       BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
-       BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
-       BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
-       set_memory((unsigned long)layout->base + layout->text_size,
-                  (layout->ro_size - layout->text_size) >> PAGE_SHIFT);
-}
-
-static void frob_ro_after_init(const struct module_layout *layout,
-                               int (*set_memory)(unsigned long start, int num_pages))
-{
-       BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
-       BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
-       BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
-       set_memory((unsigned long)layout->base + layout->ro_size,
-                  (layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT);
-}
-
-static void frob_writable_data(const struct module_layout *layout,
-                              int (*set_memory)(unsigned long start, int num_pages))
-{
-       BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
-       BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
-       BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1));
-       set_memory((unsigned long)layout->base + layout->ro_after_init_size,
-                  (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT);
-}
-
-static void module_enable_ro(const struct module *mod, bool after_init)
-{
-       if (!rodata_enabled)
-               return;
-
-       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_rodata(&mod->core_layout, set_memory_ro);
-       frob_text(&mod->init_layout, set_memory_ro);
-       frob_rodata(&mod->init_layout, set_memory_ro);
-
-       if (after_init)
-               frob_ro_after_init(&mod->core_layout, set_memory_ro);
-}
-
-static void module_enable_nx(const struct module *mod)
-{
-       frob_rodata(&mod->core_layout, set_memory_nx);
-       frob_ro_after_init(&mod->core_layout, set_memory_nx);
-       frob_writable_data(&mod->core_layout, set_memory_nx);
-       frob_rodata(&mod->init_layout, set_memory_nx);
-       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) {
-                       pr_err("%s: section %s (index %d) has invalid WRITE|EXEC flags\n",
-                               mod->name, secstrings + sechdrs[i].sh_name, i);
-                       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) {}
-static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
-                                      char *secstrings, struct module *mod)
-{
-       return 0;
-}
-#endif /*  CONFIG_STRICT_MODULE_RWX */
-
 void __weak module_memfree(void *module_region)
 {
        /*
diff --git a/kernel/module/strict_rwx.c b/kernel/module/strict_rwx.c
new file mode 100644 (file)
index 0000000..7949dfd
--- /dev/null
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Module strict rwx
+ *
+ * Copyright (C) 2015 Rusty Russell
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/set_memory.h>
+#include "internal.h"
+
+static void frob_rodata(const struct module_layout *layout,
+                int (*set_memory)(unsigned long start, int num_pages))
+{
+       BUG_ON(!PAGE_ALIGNED(layout->base));
+       BUG_ON(!PAGE_ALIGNED(layout->text_size));
+       BUG_ON(!PAGE_ALIGNED(layout->ro_size));
+       set_memory((unsigned long)layout->base + layout->text_size,
+                  (layout->ro_size - layout->text_size) >> PAGE_SHIFT);
+}
+
+static void frob_ro_after_init(const struct module_layout *layout,
+                       int (*set_memory)(unsigned long start, int num_pages))
+{
+       BUG_ON(!PAGE_ALIGNED(layout->base));
+       BUG_ON(!PAGE_ALIGNED(layout->ro_size));
+       BUG_ON(!PAGE_ALIGNED(layout->ro_after_init_size));
+       set_memory((unsigned long)layout->base + layout->ro_size,
+                  (layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT);
+}
+
+static void frob_writable_data(const struct module_layout *layout,
+                       int (*set_memory)(unsigned long start, int num_pages))
+{
+       BUG_ON(!PAGE_ALIGNED(layout->base));
+       BUG_ON(!PAGE_ALIGNED(layout->ro_after_init_size));
+       BUG_ON(!PAGE_ALIGNED(layout->size));
+       set_memory((unsigned long)layout->base + layout->ro_after_init_size,
+                  (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT);
+}
+
+void module_enable_ro(const struct module *mod, bool after_init)
+{
+       if (!rodata_enabled)
+               return;
+
+       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_rodata(&mod->core_layout, set_memory_ro);
+       frob_text(&mod->init_layout, set_memory_ro);
+       frob_rodata(&mod->init_layout, set_memory_ro);
+
+       if (after_init)
+               frob_ro_after_init(&mod->core_layout, set_memory_ro);
+}
+
+void module_enable_nx(const struct module *mod)
+{
+       frob_rodata(&mod->core_layout, set_memory_nx);
+       frob_ro_after_init(&mod->core_layout, set_memory_nx);
+       frob_writable_data(&mod->core_layout, set_memory_nx);
+       frob_rodata(&mod->init_layout, set_memory_nx);
+       frob_writable_data(&mod->init_layout, set_memory_nx);
+}
+
+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) {
+                       pr_err("%s: section %s (index %d) has invalid WRITE|EXEC flags\n",
+                              mod->name, secstrings + sechdrs[i].sh_name, i);
+                       return -ENOEXEC;
+               }
+       }
+
+       return 0;
+}