[PATCH v2 0/1] Add ro_after_init support for modules

STALE3685d

Revision v2 of 2 in this series.

4 messages, 2 authors, 2016-07-25 · open the first message on its own page

[PATCH v2 0/1] Add ro_after_init support for modules

From: Jessica Yu <hidden>
Date: 2016-07-25 09:26:26

Hi,

This patch adds ro_after_init support for modules by adding an additional
page-aligned section in the module layout. This new ro_after_init section
sits between rodata and writable data.

So, the new module layout looks like:
   [text] [rodata] [ro_after_init] [writable data]

RO after init data remains RW during init and RO protection is enabled
separately after module init runs.

Did some light testing with lkdtm compiled as a module, verified that
ro_after_init data is writable during init, and that it oopsed after attempted
writes after init. Also tested livepatch (which uses module_{enable,disable}_ro
for its own purposes) to make sure nothing broke. More testing is appreciated :-)

Some remarks on the implementation:
 * A new SHF_RO_AFTER_INIT flag is introduced in elf.h to make
   identification of .data..ro_after_init sections and the work of
   layout_sections() easier. Its chosen value is within the SHF_MASKOS
   range.
 * If a module doesn't have a ro_after_init section, then
   core_layout.ro_after_init_size just takes the value of
   core_layout.ro_size, and frob_ro_after_init() should do nothing.

Based on linux-next.

v1 here:
http://lkml.kernel.org/g/1465863198-15947-1-git-send-email-jeyu-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org

v2:
 - Add a bool after_init parameter to module_enable_ro(), it's much clearer
   than checking module->state.
 - Since the function signature for module_enable_ro() has changed, livepatch
   needs to slightly adjust its call to module_enable_ro()

Jessica Yu (1):
  modules: add ro_after_init support

 include/linux/module.h   |  6 +++--
 include/uapi/linux/elf.h |  1 +
 kernel/livepatch/core.c  |  2 +-
 kernel/module.c          | 66 +++++++++++++++++++++++++++++++++++++++---------
 4 files changed, 60 insertions(+), 15 deletions(-)

-- 
2.5.5

[PATCH v2 1/1] modules: add ro_after_init support

From: Jessica Yu <hidden>
Date: 2016-07-25 09:26:54

Add ro_after_init support for modules by adding a new page-aligned section
in the module layout (after rodata) for ro_after_init data and enabling RO
protection for that section after module init runs.

Signed-off-by: Jessica Yu <redacted>
---
 include/linux/module.h   |  6 +++--
 include/uapi/linux/elf.h |  1 +
 kernel/livepatch/core.c  |  2 +-
 kernel/module.c          | 66 +++++++++++++++++++++++++++++++++++++++---------
 4 files changed, 60 insertions(+), 15 deletions(-)
diff --git a/include/linux/module.h b/include/linux/module.h
index f777164..5255c2f 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -311,6 +311,8 @@ struct module_layout {
 	unsigned int text_size;
 	/* Size of RO section of the module (text+rodata) */
 	unsigned int ro_size;
+	/* Size of RO after init section */
+	unsigned int ro_after_init_size;
 
 #ifdef CONFIG_MODULES_TREE_LOOKUP
 	struct mod_tree_node mtn;
@@ -788,12 +790,12 @@ extern int module_sysfs_initialized;
 #ifdef CONFIG_DEBUG_SET_MODULE_RONX
 extern void set_all_modules_text_rw(void);
 extern void set_all_modules_text_ro(void);
-extern void module_enable_ro(const struct module *mod);
+extern void module_enable_ro(const struct module *mod, bool after_init);
 extern void module_disable_ro(const struct module *mod);
 #else
 static inline void set_all_modules_text_rw(void) { }
 static inline void set_all_modules_text_ro(void) { }
-static inline void module_enable_ro(const struct module *mod) { }
+static inline void module_enable_ro(const struct module *mod, bool after_init) { }
 static inline void module_disable_ro(const struct module *mod) { }
 #endif
 
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index cb4a72f..70b172ba 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -286,6 +286,7 @@ typedef struct elf64_phdr {
 #define SHF_ALLOC		0x2
 #define SHF_EXECINSTR		0x4
 #define SHF_RELA_LIVEPATCH	0x00100000
+#define SHF_RO_AFTER_INIT	0x00200000
 #define SHF_MASKPROC		0xf0000000
 
 /* special section indexes */
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 5c2bc10..8bbe507 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -309,7 +309,7 @@ static int klp_write_object_relocations(struct module *pmod,
 			break;
 	}
 
-	module_enable_ro(pmod);
+	module_enable_ro(pmod, true);
 	return ret;
 }
 
diff --git a/kernel/module.c b/kernel/module.c
index e70a2fa..e697144 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1858,10 +1858,11 @@ static void mod_sysfs_teardown(struct module *mod)
  * from modification and any data from execution.
  *
  * General layout of module is:
- *          [text] [read-only-data] [writable data]
- * text_size -----^                ^               ^
- * ro_size ------------------------|               |
- * size -------------------------------------------|
+ *          [text] [read-only-data] [ro-after-init] [writable data]
+ * text_size -----^                ^               ^               ^
+ * ro_size ------------------------|               |               |
+ * ro_after_init_size -----------------------------|               |
+ * size -----------------------------------------------------------|
  *
  * These values are always page-aligned (as is base)
  */
@@ -1884,14 +1885,24 @@ static void frob_rodata(const struct module_layout *layout,
 		   (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_size & (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_size,
-		   (layout->size - layout->ro_size) >> PAGE_SHIFT);
+	set_memory((unsigned long)layout->base + layout->ro_after_init_size,
+		   (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT);
 }
 
 /* livepatching wants to disable read-only so it can frob module. */
@@ -1899,21 +1910,26 @@ void module_disable_ro(const struct module *mod)
 {
 	frob_text(&mod->core_layout, set_memory_rw);
 	frob_rodata(&mod->core_layout, set_memory_rw);
+	frob_ro_after_init(&mod->core_layout, set_memory_rw);
 	frob_text(&mod->init_layout, set_memory_rw);
 	frob_rodata(&mod->init_layout, set_memory_rw);
 }
 
-void module_enable_ro(const struct module *mod)
+void module_enable_ro(const struct module *mod, bool after_init)
 {
 	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);
@@ -1922,6 +1938,7 @@ static void module_enable_nx(const struct module *mod)
 static void module_disable_nx(const struct module *mod)
 {
 	frob_rodata(&mod->core_layout, set_memory_x);
+	frob_ro_after_init(&mod->core_layout, set_memory_x);
 	frob_writable_data(&mod->core_layout, set_memory_x);
 	frob_rodata(&mod->init_layout, set_memory_x);
 	frob_writable_data(&mod->init_layout, set_memory_x);
@@ -1964,6 +1981,8 @@ static void disable_ro_nx(const struct module_layout *layout)
 	frob_text(layout, set_memory_rw);
 	frob_rodata(layout, set_memory_rw);
 	frob_rodata(layout, set_memory_x);
+	frob_ro_after_init(layout, set_memory_rw);
+	frob_ro_after_init(layout, set_memory_x);
 	frob_writable_data(layout, set_memory_x);
 }
 
@@ -2306,6 +2325,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
 		 * finder in the two loops below */
 		{ SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL },
 		{ SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL },
+		{ SHF_RO_AFTER_INIT | SHF_ALLOC, ARCH_SHF_SMALL },
 		{ SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL },
 		{ ARCH_SHF_SMALL | SHF_ALLOC, 0 }
 	};
@@ -2337,7 +2357,11 @@ static void layout_sections(struct module *mod, struct load_info *info)
 			mod->core_layout.size = debug_align(mod->core_layout.size);
 			mod->core_layout.ro_size = mod->core_layout.size;
 			break;
-		case 3: /* whole core */
+		case 2: /* RO after init */
+			mod->core_layout.size = debug_align(mod->core_layout.size);
+			mod->core_layout.ro_after_init_size = mod->core_layout.size;
+			break;
+		case 4: /* whole core */
 			mod->core_layout.size = debug_align(mod->core_layout.size);
 			break;
 		}
@@ -2367,7 +2391,14 @@ static void layout_sections(struct module *mod, struct load_info *info)
 			mod->init_layout.size = debug_align(mod->init_layout.size);
 			mod->init_layout.ro_size = mod->init_layout.size;
 			break;
-		case 3: /* whole init */
+		case 2:
+			/*
+			 * RO after init doesn't apply to init_layout (only
+			 * core_layout), so it just takes the value of ro_size.
+			 */
+			mod->init_layout.ro_after_init_size = mod->init_layout.ro_size;
+			break;
+		case 4: /* whole init */
 			mod->init_layout.size = debug_align(mod->init_layout.size);
 			break;
 		}
@@ -3173,6 +3204,7 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
 {
 	/* Module within temporary copy. */
 	struct module *mod;
+	unsigned int ndx;
 	int err;
 
 	mod = setup_load_info(info, flags);
@@ -3192,6 +3224,15 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
 	/* We will do a special allocation for per-cpu sections later. */
 	info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;
 
+	/*
+	 * Mark ro_after_init section with SHF_RO_AFTER_INIT so that
+	 * layout_sections() can put it in the right place.
+	 * Note: ro_after_init sections also have SHF_{WRITE,ALLOC} set.
+	 */
+	ndx = find_sec(info, ".data..ro_after_init");
+	if (ndx)
+		info->sechdrs[ndx].sh_flags |= SHF_RO_AFTER_INIT;
+
 	/* Determine total sizes, and put offsets in sh_entsize.  For now
 	   this is done generically; there doesn't appear to be any
 	   special cases for the architectures. */
@@ -3358,12 +3399,14 @@ static noinline int do_init_module(struct module *mod)
 	/* Switch to core kallsyms now init is done: kallsyms may be walking! */
 	rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms);
 #endif
+	module_enable_ro(mod, true);
 	mod_tree_remove_init(mod);
 	disable_ro_nx(&mod->init_layout);
 	module_arch_freeing_init(mod);
 	mod->init_layout.base = NULL;
 	mod->init_layout.size = 0;
 	mod->init_layout.ro_size = 0;
+	mod->init_layout.ro_after_init_size = 0;
 	mod->init_layout.text_size = 0;
 	/*
 	 * We want to free module_init, but be aware that kallsyms may be
@@ -3455,8 +3498,7 @@ static int complete_formation(struct module *mod, struct load_info *info)
 	/* This relies on module_mutex for list integrity. */
 	module_bug_finalize(info->hdr, info->sechdrs, mod);
 
-	/* Set RO and NX regions */
-	module_enable_ro(mod);
+	module_enable_ro(mod, false);
 	module_enable_nx(mod);
 
 	/* Mark state as coming so strong_try_module_get() ignores us,
-- 
2.5.5

Re: modules: add ro_after_init support

From: Jessica Yu <hidden>
Date: 2016-07-25 10:02:04

+++ Jessica Yu [25/07/16 05:25 -0400]:
quoted hunk
Add ro_after_init support for modules by adding a new page-aligned section
in the module layout (after rodata) for ro_after_init data and enabling RO
protection for that section after module init runs.

Signed-off-by: Jessica Yu <redacted>
---
include/linux/module.h   |  6 +++--
include/uapi/linux/elf.h |  1 +
kernel/livepatch/core.c  |  2 +-
kernel/module.c          | 66 +++++++++++++++++++++++++++++++++++++++---------
4 files changed, 60 insertions(+), 15 deletions(-)
diff --git a/include/linux/module.h b/include/linux/module.h
index f777164..5255c2f 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -311,6 +311,8 @@ struct module_layout {
	unsigned int text_size;
	/* Size of RO section of the module (text+rodata) */
	unsigned int ro_size;
+	/* Size of RO after init section */
+	unsigned int ro_after_init_size;

#ifdef CONFIG_MODULES_TREE_LOOKUP
	struct mod_tree_node mtn;
@@ -788,12 +790,12 @@ extern int module_sysfs_initialized;
#ifdef CONFIG_DEBUG_SET_MODULE_RONX
extern void set_all_modules_text_rw(void);
extern void set_all_modules_text_ro(void);
-extern void module_enable_ro(const struct module *mod);
+extern void module_enable_ro(const struct module *mod, bool after_init);
extern void module_disable_ro(const struct module *mod);
#else
static inline void set_all_modules_text_rw(void) { }
static inline void set_all_modules_text_ro(void) { }
-static inline void module_enable_ro(const struct module *mod) { }
+static inline void module_enable_ro(const struct module *mod, bool after_init) { }
static inline void module_disable_ro(const struct module *mod) { }
#endif
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index cb4a72f..70b172ba 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -286,6 +286,7 @@ typedef struct elf64_phdr {
#define SHF_ALLOC		0x2
#define SHF_EXECINSTR		0x4
#define SHF_RELA_LIVEPATCH	0x00100000
+#define SHF_RO_AFTER_INIT	0x00200000
#define SHF_MASKPROC		0xf0000000

/* special section indexes */
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 5c2bc10..8bbe507 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -309,7 +309,7 @@ static int klp_write_object_relocations(struct module *pmod,
			break;
	}

-	module_enable_ro(pmod);
+	module_enable_ro(pmod, true);
There is a slight quirk here in that klp_init_object_loaded() (which
calls klp_write_object_relocations()) can be called either during
patch module init (during patch registration) or after init (e.g.,
when a previously unloaded to-be-patched module is loaded). AFAIK
patch modules themselves don't use .data..ro_after_init sections, so
it's probably fine to set after_init to be true here for now. But I
still need to think some more about the case where we try to patch
data from another module marked __ro_after_init.

Re: [PATCH v2 1/1] modules: add ro_after_init support

From: Kees Cook <hidden>
Date: 2016-07-25 18:04:36

On Mon, Jul 25, 2016 at 2:25 AM, Jessica Yu [off-list ref] wrote:
Add ro_after_init support for modules by adding a new page-aligned section
in the module layout (after rodata) for ro_after_init data and enabling RO
protection for that section after module init runs.

Signed-off-by: Jessica Yu <redacted>
Acked-by: Kees Cook <redacted>

Thanks!

-Kees
quoted hunk
---
 include/linux/module.h   |  6 +++--
 include/uapi/linux/elf.h |  1 +
 kernel/livepatch/core.c  |  2 +-
 kernel/module.c          | 66 +++++++++++++++++++++++++++++++++++++++---------
 4 files changed, 60 insertions(+), 15 deletions(-)
diff --git a/include/linux/module.h b/include/linux/module.h
index f777164..5255c2f 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -311,6 +311,8 @@ struct module_layout {
        unsigned int text_size;
        /* Size of RO section of the module (text+rodata) */
        unsigned int ro_size;
+       /* Size of RO after init section */
+       unsigned int ro_after_init_size;

 #ifdef CONFIG_MODULES_TREE_LOOKUP
        struct mod_tree_node mtn;
@@ -788,12 +790,12 @@ extern int module_sysfs_initialized;
 #ifdef CONFIG_DEBUG_SET_MODULE_RONX
 extern void set_all_modules_text_rw(void);
 extern void set_all_modules_text_ro(void);
-extern void module_enable_ro(const struct module *mod);
+extern void module_enable_ro(const struct module *mod, bool after_init);
 extern void module_disable_ro(const struct module *mod);
 #else
 static inline void set_all_modules_text_rw(void) { }
 static inline void set_all_modules_text_ro(void) { }
-static inline void module_enable_ro(const struct module *mod) { }
+static inline void module_enable_ro(const struct module *mod, bool after_init) { }
 static inline void module_disable_ro(const struct module *mod) { }
 #endif
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index cb4a72f..70b172ba 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -286,6 +286,7 @@ typedef struct elf64_phdr {
 #define SHF_ALLOC              0x2
 #define SHF_EXECINSTR          0x4
 #define SHF_RELA_LIVEPATCH     0x00100000
+#define SHF_RO_AFTER_INIT      0x00200000
 #define SHF_MASKPROC           0xf0000000

 /* special section indexes */
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 5c2bc10..8bbe507 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -309,7 +309,7 @@ static int klp_write_object_relocations(struct module *pmod,
                        break;
        }

-       module_enable_ro(pmod);
+       module_enable_ro(pmod, true);
        return ret;
 }
diff --git a/kernel/module.c b/kernel/module.c
index e70a2fa..e697144 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1858,10 +1858,11 @@ static void mod_sysfs_teardown(struct module *mod)
  * from modification and any data from execution.
  *
  * General layout of module is:
- *          [text] [read-only-data] [writable data]
- * text_size -----^                ^               ^
- * ro_size ------------------------|               |
- * size -------------------------------------------|
+ *          [text] [read-only-data] [ro-after-init] [writable data]
+ * text_size -----^                ^               ^               ^
+ * ro_size ------------------------|               |               |
+ * ro_after_init_size -----------------------------|               |
+ * size -----------------------------------------------------------|
  *
  * These values are always page-aligned (as is base)
  */
@@ -1884,14 +1885,24 @@ static void frob_rodata(const struct module_layout *layout,
                   (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_size & (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_size,
-                  (layout->size - layout->ro_size) >> PAGE_SHIFT);
+       set_memory((unsigned long)layout->base + layout->ro_after_init_size,
+                  (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT);
 }

 /* livepatching wants to disable read-only so it can frob module. */
@@ -1899,21 +1910,26 @@ void module_disable_ro(const struct module *mod)
 {
        frob_text(&mod->core_layout, set_memory_rw);
        frob_rodata(&mod->core_layout, set_memory_rw);
+       frob_ro_after_init(&mod->core_layout, set_memory_rw);
        frob_text(&mod->init_layout, set_memory_rw);
        frob_rodata(&mod->init_layout, set_memory_rw);
 }

-void module_enable_ro(const struct module *mod)
+void module_enable_ro(const struct module *mod, bool after_init)
 {
        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);
@@ -1922,6 +1938,7 @@ static void module_enable_nx(const struct module *mod)
 static void module_disable_nx(const struct module *mod)
 {
        frob_rodata(&mod->core_layout, set_memory_x);
+       frob_ro_after_init(&mod->core_layout, set_memory_x);
        frob_writable_data(&mod->core_layout, set_memory_x);
        frob_rodata(&mod->init_layout, set_memory_x);
        frob_writable_data(&mod->init_layout, set_memory_x);
@@ -1964,6 +1981,8 @@ static void disable_ro_nx(const struct module_layout *layout)
        frob_text(layout, set_memory_rw);
        frob_rodata(layout, set_memory_rw);
        frob_rodata(layout, set_memory_x);
+       frob_ro_after_init(layout, set_memory_rw);
+       frob_ro_after_init(layout, set_memory_x);
        frob_writable_data(layout, set_memory_x);
 }
@@ -2306,6 +2325,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
                 * finder in the two loops below */
                { SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL },
                { SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL },
+               { SHF_RO_AFTER_INIT | SHF_ALLOC, ARCH_SHF_SMALL },
                { SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL },
                { ARCH_SHF_SMALL | SHF_ALLOC, 0 }
        };
@@ -2337,7 +2357,11 @@ static void layout_sections(struct module *mod, struct load_info *info)
                        mod->core_layout.size = debug_align(mod->core_layout.size);
                        mod->core_layout.ro_size = mod->core_layout.size;
                        break;
-               case 3: /* whole core */
+               case 2: /* RO after init */
+                       mod->core_layout.size = debug_align(mod->core_layout.size);
+                       mod->core_layout.ro_after_init_size = mod->core_layout.size;
+                       break;
+               case 4: /* whole core */
                        mod->core_layout.size = debug_align(mod->core_layout.size);
                        break;
                }
@@ -2367,7 +2391,14 @@ static void layout_sections(struct module *mod, struct load_info *info)
                        mod->init_layout.size = debug_align(mod->init_layout.size);
                        mod->init_layout.ro_size = mod->init_layout.size;
                        break;
-               case 3: /* whole init */
+               case 2:
+                       /*
+                        * RO after init doesn't apply to init_layout (only
+                        * core_layout), so it just takes the value of ro_size.
+                        */
+                       mod->init_layout.ro_after_init_size = mod->init_layout.ro_size;
+                       break;
+               case 4: /* whole init */
                        mod->init_layout.size = debug_align(mod->init_layout.size);
                        break;
                }
@@ -3173,6 +3204,7 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
 {
        /* Module within temporary copy. */
        struct module *mod;
+       unsigned int ndx;
        int err;

        mod = setup_load_info(info, flags);
@@ -3192,6 +3224,15 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
        /* We will do a special allocation for per-cpu sections later. */
        info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;

+       /*
+        * Mark ro_after_init section with SHF_RO_AFTER_INIT so that
+        * layout_sections() can put it in the right place.
+        * Note: ro_after_init sections also have SHF_{WRITE,ALLOC} set.
+        */
+       ndx = find_sec(info, ".data..ro_after_init");
+       if (ndx)
+               info->sechdrs[ndx].sh_flags |= SHF_RO_AFTER_INIT;
+
        /* Determine total sizes, and put offsets in sh_entsize.  For now
           this is done generically; there doesn't appear to be any
           special cases for the architectures. */
@@ -3358,12 +3399,14 @@ static noinline int do_init_module(struct module *mod)
        /* Switch to core kallsyms now init is done: kallsyms may be walking! */
        rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms);
 #endif
+       module_enable_ro(mod, true);
        mod_tree_remove_init(mod);
        disable_ro_nx(&mod->init_layout);
        module_arch_freeing_init(mod);
        mod->init_layout.base = NULL;
        mod->init_layout.size = 0;
        mod->init_layout.ro_size = 0;
+       mod->init_layout.ro_after_init_size = 0;
        mod->init_layout.text_size = 0;
        /*
         * We want to free module_init, but be aware that kallsyms may be
@@ -3455,8 +3498,7 @@ static int complete_formation(struct module *mod, struct load_info *info)
        /* This relies on module_mutex for list integrity. */
        module_bug_finalize(info->hdr, info->sechdrs, mod);

-       /* Set RO and NX regions */
-       module_enable_ro(mod);
+       module_enable_ro(mod, false);
        module_enable_nx(mod);

        /* Mark state as coming so strong_try_module_get() ignores us,
--
2.5.5


-- 
Kees Cook
Brillo & Chrome OS Security
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help