linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Undoing module RONX protection
@ 2011-04-18  9:23 Jan Glauber
  2011-04-18  9:28 ` Christoph Hellwig
  0 siblings, 1 reply; 12+ messages in thread
From: Jan Glauber @ 2011-04-18  9:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: castet.matthieu, sliakh.lkml, jiang, rusty, mingo

While debugging I stumbled over two problems in the code that protects module
pages.

First issue is that disabling the protection before freeing init or unload of
a module is not symmetric with the enablement. For instance, if pages are set
to RO the page range from module_core to module_core + core_ro_size is
protected. If a module is unloaded the page range from module_core to
module_core + core_size is set back to RW.
So pages that were not set to RO are also changed to RW.
This is not critical but IMHO it should be symmetric.

Second issue is that while set_memory_rw & set_memory_ro are used for
RO/RW changes only set_memory_nx is involved for NX/X. One would await that
the inverse function is called when the NX protection should be removed,
which is not the case here, unless I'm missing something.

The following patch addresses both issues. Works on s390. Boot tested on x86.

Please comment,
Jan

---------

Use the proper function to reset the NX page protection and only reset pages
that were previously protected during module load. Export the missing
set_memory_x for s390.

Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
---
 arch/s390/include/asm/cacheflush.h |    1 +
 arch/s390/mm/pageattr.c            |    6 ++++++
 kernel/module.c                    |   25 +++++++++++++------------
 3 files changed, 20 insertions(+), 12 deletions(-)

--- a/arch/s390/include/asm/cacheflush.h
+++ b/arch/s390/include/asm/cacheflush.h
@@ -11,5 +11,6 @@ void kernel_map_pages(struct page *page,
 int set_memory_ro(unsigned long addr, int numpages);
 int set_memory_rw(unsigned long addr, int numpages);
 int set_memory_nx(unsigned long addr, int numpages);
+int set_memory_x(unsigned long addr, int numpages);
 
 #endif /* _S390_CACHEFLUSH_H */
--- a/arch/s390/mm/pageattr.c
+++ b/arch/s390/mm/pageattr.c
@@ -54,3 +54,9 @@ int set_memory_nx(unsigned long addr, in
 	return 0;
 }
 EXPORT_SYMBOL_GPL(set_memory_nx);
+
+int set_memory_x(unsigned long addr, int numpages)
+{
+	return 0;
+}
+EXPORT_SYMBOL_GPL(set_memory_x);
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1607,22 +1607,23 @@ static void set_section_ro_nx(void *base
 	}
 }
 
-/* Setting memory back to RW+NX before releasing it */
+/* Setting memory back to W+X before releasing it */
 void unset_section_ro_nx(struct module *mod, void *module_region)
 {
-	unsigned long total_pages;
-
 	if (mod->module_core == module_region) {
-		/* Set core as NX+RW */
-		total_pages = MOD_NUMBER_OF_PAGES(mod->module_core, mod->core_size);
-		set_memory_nx((unsigned long)mod->module_core, total_pages);
-		set_memory_rw((unsigned long)mod->module_core, total_pages);
-
+		set_page_attributes(mod->module_core + mod->core_text_size,
+			mod->module_core + mod->core_size,
+			set_memory_x);
+		set_page_attributes(mod->module_core,
+			mod->module_core + mod->core_ro_size,
+			set_memory_rw);
 	} else if (mod->module_init == module_region) {
-		/* Set init as NX+RW */
-		total_pages = MOD_NUMBER_OF_PAGES(mod->module_init, mod->init_size);
-		set_memory_nx((unsigned long)mod->module_init, total_pages);
-		set_memory_rw((unsigned long)mod->module_init, total_pages);
+		set_page_attributes(mod->module_init + mod->init_text_size,
+			mod->module_init + mod->init_size,
+			set_memory_x);
+		set_page_attributes(mod->module_init,
+			mod->module_init + mod->init_ro_size,
+			set_memory_rw);
 	}
 }
 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Undoing module RONX protection
  2011-04-18  9:23 Undoing module RONX protection Jan Glauber
@ 2011-04-18  9:28 ` Christoph Hellwig
  2011-04-18 10:43   ` Rusty Russell
  2011-04-18 12:40   ` Undoing module RONX protection Jan Glauber
  0 siblings, 2 replies; 12+ messages in thread
From: Christoph Hellwig @ 2011-04-18  9:28 UTC (permalink / raw)
  To: Jan Glauber
  Cc: linux-kernel, castet.matthieu, sliakh.lkml, jiang, rusty, mingo

> +int set_memory_x(unsigned long addr, int numpages)
> +{
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(set_memory_x);

No need to export this one.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Undoing module RONX protection
  2011-04-18  9:28 ` Christoph Hellwig
@ 2011-04-18 10:43   ` Rusty Russell
  2011-04-21 14:19     ` Jan Glauber
  2011-04-18 12:40   ` Undoing module RONX protection Jan Glauber
  1 sibling, 1 reply; 12+ messages in thread
From: Rusty Russell @ 2011-04-18 10:43 UTC (permalink / raw)
  To: Christoph Hellwig, Jan Glauber
  Cc: linux-kernel, castet.matthieu, sliakh.lkml, jiang, mingo

On Mon, 18 Apr 2011 11:23:48 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> While debugging I stumbled over two problems in the code that protects module
> pages.
> 
> First issue is that disabling the protection before freeing init or unload of
> a module is not symmetric with the enablement. For instance, if pages are set
> to RO the page range from module_core to module_core + core_ro_size is
> protected. If a module is unloaded the page range from module_core to
> module_core + core_size is set back to RW.
> So pages that were not set to RO are also changed to RW.
> This is not critical but IMHO it should be symmetric.
> 
> Second issue is that while set_memory_rw & set_memory_ro are used for
> RO/RW changes only set_memory_nx is involved for NX/X. One would await that
> the inverse function is called when the NX protection should be removed,
> which is not the case here, unless I'm missing something.
> 
> The following patch addresses both issues. Works on s390. Boot tested on x86.
> 
> Please comment,

Applied, minus the S/390 EXPORT_SYMBOL which Christoph pointed out.  I
turned your mail into the commit message, since it was clearer and more
verbose.  I don't see why they would be different.

Might have been nicer as three separate patches, in future.

Thanks!
Rusty.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Undoing module RONX protection
  2011-04-18  9:28 ` Christoph Hellwig
  2011-04-18 10:43   ` Rusty Russell
@ 2011-04-18 12:40   ` Jan Glauber
  1 sibling, 0 replies; 12+ messages in thread
From: Jan Glauber @ 2011-04-18 12:40 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-kernel, castet.matthieu, sliakh.lkml, jiang, rusty, mingo

On Mon, Apr 18, 2011 at 05:28:01AM -0400, Christoph Hellwig wrote:
> > +int set_memory_x(unsigned long addr, int numpages)
> > +{
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(set_memory_x);
> 
> No need to export this one.

True. Also for the other exports in that file. Will remove them.

--Jan

> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Undoing module RONX protection
  2011-04-18 10:43   ` Rusty Russell
@ 2011-04-21 14:19     ` Jan Glauber
  2011-04-27  5:12       ` Undoing module RONX protection fix Rusty Russell
  0 siblings, 1 reply; 12+ messages in thread
From: Jan Glauber @ 2011-04-21 14:19 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Christoph Hellwig, linux-kernel, castet.matthieu, sliakh.lkml,
	jiang, mingo

On Mon, Apr 18, 2011 at 08:13:36PM +0930, Rusty Russell wrote:
> On Mon, 18 Apr 2011 11:23:48 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> > While debugging I stumbled over two problems in the code that protects module
> > pages.
> > 
> > First issue is that disabling the protection before freeing init or unload of
> > a module is not symmetric with the enablement. For instance, if pages are set
> > to RO the page range from module_core to module_core + core_ro_size is
> > protected. If a module is unloaded the page range from module_core to
> > module_core + core_size is set back to RW.
> > So pages that were not set to RO are also changed to RW.
> > This is not critical but IMHO it should be symmetric.
> > 
> > Second issue is that while set_memory_rw & set_memory_ro are used for
> > RO/RW changes only set_memory_nx is involved for NX/X. One would await that
> > the inverse function is called when the NX protection should be removed,
> > which is not the case here, unless I'm missing something.
> > 
> > The following patch addresses both issues. Works on s390. Boot tested on x86.
> > 
> > Please comment,
> 
> Applied, minus the S/390 EXPORT_SYMBOL which Christoph pointed out.  I
> turned your mail into the commit message, since it was clearer and more
> verbose.  I don't see why they would be different.

There's a bug in my patch which just killed one of my s390 machines.
Can you merge this with the previuos patch?

thanks, Jan
---

From: Jan Glauber <jang@linux.vnet.ibm.com>

A module may not have an init part so set_page_attributes may try to
change an invalid page range. Modifying page 0 is fatal on s390. Bail
out in case the module_core or module_init is not present.

Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
---
 kernel/module.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1610,14 +1610,14 @@ static void set_section_ro_nx(void *base
 /* Setting memory back to W+X before releasing it */
 void unset_section_ro_nx(struct module *mod, void *module_region)
 {
-	if (mod->module_core == module_region) {
+	if (mod->module_core && mod->module_core == module_region) {
 		set_page_attributes(mod->module_core + mod->core_text_size,
 			mod->module_core + mod->core_size,
 			set_memory_x);
 		set_page_attributes(mod->module_core,
 			mod->module_core + mod->core_ro_size,
 			set_memory_rw);
-	} else if (mod->module_init == module_region) {
+	} else if (mod->module_init && mod->module_init == module_region) {
 		set_page_attributes(mod->module_init + mod->init_text_size,
 			mod->module_init + mod->init_size,
 			set_memory_x);

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Undoing module RONX protection fix
  2011-04-21 14:19     ` Jan Glauber
@ 2011-04-27  5:12       ` Rusty Russell
  2011-04-28 10:08         ` Jan Glauber
  0 siblings, 1 reply; 12+ messages in thread
From: Rusty Russell @ 2011-04-27  5:12 UTC (permalink / raw)
  To: Jan Glauber
  Cc: Christoph Hellwig, linux-kernel, castet.matthieu, sliakh.lkml,
	jiang, mingo

On Thu, 21 Apr 2011 16:19:49 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> On Mon, Apr 18, 2011 at 08:13:36PM +0930, Rusty Russell wrote:
> > On Mon, 18 Apr 2011 11:23:48 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> > > While debugging I stumbled over two problems in the code that protects module
> > > pages.
> > > 
> > > First issue is that disabling the protection before freeing init or unload of
> > > a module is not symmetric with the enablement. For instance, if pages are set
> > > to RO the page range from module_core to module_core + core_ro_size is
> > > protected. If a module is unloaded the page range from module_core to
> > > module_core + core_size is set back to RW.
> > > So pages that were not set to RO are also changed to RW.
> > > This is not critical but IMHO it should be symmetric.
> > > 
> > > Second issue is that while set_memory_rw & set_memory_ro are used for
> > > RO/RW changes only set_memory_nx is involved for NX/X. One would await that
> > > the inverse function is called when the NX protection should be removed,
> > > which is not the case here, unless I'm missing something.
> > > 
> > > The following patch addresses both issues. Works on s390. Boot tested on x86.
> > > 
> > > Please comment,
> > 
> > Applied, minus the S/390 EXPORT_SYMBOL which Christoph pointed out.  I
> > turned your mail into the commit message, since it was clearer and more
> > verbose.  I don't see why they would be different.
> 
> There's a bug in my patch which just killed one of my s390 machines.
> Can you merge this with the previuos patch?

Hmm...

Applied, but that function is really kind of silly.  We should probably
just split into unset_section_ro_nx() into unset_module_init_ro_nx() and
unset_module_core_ro_nx().

(And why isn't that function static anyway?)

Patch appreciated :)
Rusty.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Undoing module RONX protection fix
  2011-04-27  5:12       ` Undoing module RONX protection fix Rusty Russell
@ 2011-04-28 10:08         ` Jan Glauber
  2011-04-28 11:36           ` Rusty Russell
  0 siblings, 1 reply; 12+ messages in thread
From: Jan Glauber @ 2011-04-28 10:08 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Christoph Hellwig, linux-kernel, castet.matthieu, sliakh.lkml,
	jiang, mingo

On Wed, 2011-04-27 at 14:42 +0930, Rusty Russell wrote:
> On Thu, 21 Apr 2011 16:19:49 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> > On Mon, Apr 18, 2011 at 08:13:36PM +0930, Rusty Russell wrote:
> > > On Mon, 18 Apr 2011 11:23:48 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> > > > While debugging I stumbled over two problems in the code that protects module
> > > > pages.
> > > > 
> > > > First issue is that disabling the protection before freeing init or unload of
> > > > a module is not symmetric with the enablement. For instance, if pages are set
> > > > to RO the page range from module_core to module_core + core_ro_size is
> > > > protected. If a module is unloaded the page range from module_core to
> > > > module_core + core_size is set back to RW.
> > > > So pages that were not set to RO are also changed to RW.
> > > > This is not critical but IMHO it should be symmetric.
> > > > 
> > > > Second issue is that while set_memory_rw & set_memory_ro are used for
> > > > RO/RW changes only set_memory_nx is involved for NX/X. One would await that
> > > > the inverse function is called when the NX protection should be removed,
> > > > which is not the case here, unless I'm missing something.
> > > > 
> > > > The following patch addresses both issues. Works on s390. Boot tested on x86.
> > > > 
> > > > Please comment,
> > > 
> > > Applied, minus the S/390 EXPORT_SYMBOL which Christoph pointed out.  I
> > > turned your mail into the commit message, since it was clearer and more
> > > verbose.  I don't see why they would be different.
> > 
> > There's a bug in my patch which just killed one of my s390 machines.
> > Can you merge this with the previuos patch?
> 
> Hmm...
> 
> Applied, but that function is really kind of silly.  We should probably
> just split into unset_section_ro_nx() into unset_module_init_ro_nx() and
> unset_module_core_ro_nx().
> 
> (And why isn't that function static anyway?)
> 
> Patch appreciated :)
> Rusty.

How about this?

To be honest I don't like the inverse naming like in unset no-execute
too much, it makes me feel dizzy. But I wanted to keep the changes minimal.

Jan
------

Split the unprotect function into a function per section to make
the code more readable and add the missing static declaration.

Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
---
 kernel/module.c |   47 ++++++++++++++++++++++++++---------------------
 1 file changed, 26 insertions(+), 21 deletions(-)

--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1607,24 +1607,28 @@ static void set_section_ro_nx(void *base
 	}
 }
 
-/* Setting memory back to W+X before releasing it */
-void unset_section_ro_nx(struct module *mod, void *module_region)
+static void unset_module_core_ro_nx(struct module *mod)
 {
-	if (mod->module_core && mod->module_core == module_region) {
-		set_page_attributes(mod->module_core + mod->core_text_size,
-			mod->module_core + mod->core_size,
-			set_memory_x);
-		set_page_attributes(mod->module_core,
-			mod->module_core + mod->core_ro_size,
-			set_memory_rw);
-	} else if (mod->module_init && mod->module_init == module_region) {
-		set_page_attributes(mod->module_init + mod->init_text_size,
-			mod->module_init + mod->init_size,
-			set_memory_x);
-		set_page_attributes(mod->module_init,
-			mod->module_init + mod->init_ro_size,
-			set_memory_rw);
-	}
+	if (mod->module_core == NULL)
+		return;
+	set_page_attributes(mod->module_core + mod->core_text_size,
+		mod->module_core + mod->core_size,
+		set_memory_x);
+	set_page_attributes(mod->module_core,
+		mod->module_core + mod->core_ro_size,
+		set_memory_rw);
+}
+
+static void unset_module_init_ro_nx(struct module *mod)
+{
+	if (mod->module_init == NULL)
+		return;
+	set_page_attributes(mod->module_init + mod->init_text_size,
+		mod->module_init + mod->init_size,
+		set_memory_x);
+	set_page_attributes(mod->module_init,
+		mod->module_init + mod->init_ro_size,
+		set_memory_rw);
 }
 
 /* Iterate through all modules and set each module's text as RW */
@@ -1670,7 +1674,8 @@ void set_all_modules_text_ro()
 }
 #else
 static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { }
-static inline void unset_section_ro_nx(struct module *mod, void *module_region) { }
+static void unset_module_core_ro_nx(struct module *mod) { }
+static void unset_module_init_ro_nx(struct module *mod) { }
 #endif
 
 /* Free a module, remove from lists, etc. */
@@ -1697,7 +1702,7 @@ static void free_module(struct module *m
 	destroy_params(mod->kp, mod->num_kp);
 
 	/* This may be NULL, but that's OK */
-	unset_section_ro_nx(mod, mod->module_init);
+	unset_module_init_ro_nx(mod);
 	module_free(mod, mod->module_init);
 	kfree(mod->args);
 	percpu_modfree(mod);
@@ -1706,7 +1711,7 @@ static void free_module(struct module *m
 	lockdep_free_key_range(mod->module_core, mod->core_size);
 
 	/* Finally, free the core (containing the module structure) */
-	unset_section_ro_nx(mod, mod->module_core);
+	unset_module_core_ro_nx(mod);
 	module_free(mod, mod->module_core);
 
 #ifdef CONFIG_MPU
@@ -2932,7 +2937,7 @@ SYSCALL_DEFINE3(init_module, void __user
 	mod->symtab = mod->core_symtab;
 	mod->strtab = mod->core_strtab;
 #endif
-	unset_section_ro_nx(mod, mod->module_init);
+	unset_module_init_ro_nx(mod);
 	module_free(mod, mod->module_init);
 	mod->module_init = NULL;
 	mod->init_size = 0;



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Undoing module RONX protection fix
  2011-04-28 10:08         ` Jan Glauber
@ 2011-04-28 11:36           ` Rusty Russell
  2011-04-28 13:43             ` Jan Glauber
  0 siblings, 1 reply; 12+ messages in thread
From: Rusty Russell @ 2011-04-28 11:36 UTC (permalink / raw)
  To: Jan Glauber
  Cc: Christoph Hellwig, linux-kernel, castet.matthieu, sliakh.lkml,
	jiang, mingo

On Thu, 28 Apr 2011 12:08:20 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> How about this?
> 
> To be honest I don't like the inverse naming like in unset no-execute
> too much, it makes me feel dizzy. But I wanted to keep the changes
> minimal.

Yes, it should probably just be called protect_module_pages and
unprotect_module_pages.  The current names provide far too much
information.

But going back a bit, how did we end up with a NULL mod->module_init and
yet module->init_text_size, mod->init_size or mod->init_ro_size
non-zero?

Because if start == end, set_page_attributes() is a noop, right?

Confused,
Rusty.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Undoing module RONX protection fix
  2011-04-28 11:36           ` Rusty Russell
@ 2011-04-28 13:43             ` Jan Glauber
  2011-04-29  4:41               ` Rusty Russell
  0 siblings, 1 reply; 12+ messages in thread
From: Jan Glauber @ 2011-04-28 13:43 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Christoph Hellwig, linux-kernel, castet.matthieu, sliakh.lkml,
	jiang, mingo

On Thu, Apr 28, 2011 at 09:06:39PM +0930, Rusty Russell wrote:
> On Thu, 28 Apr 2011 12:08:20 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> > How about this?
> > 
> > To be honest I don't like the inverse naming like in unset no-execute
> > too much, it makes me feel dizzy. But I wanted to keep the changes
> > minimal.
> 
> Yes, it should probably just be called protect_module_pages and
> unprotect_module_pages.  The current names provide far too much
> information.
> 
> But going back a bit, how did we end up with a NULL mod->module_init and
> yet module->init_text_size, mod->init_size or mod->init_ro_size
> non-zero?

printk'ing this reveals that mod->init_ro_size is not 0 but 0x1000.
Therefore the first page was modified.

Looks like init_ro_size is missing the reset to zero at the end of the init_module
syscall. Next patch ? ;-

> Because if start == end, set_page_attributes() is a noop, right?

Right.

> Confused,
> Rusty.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Undoing module RONX protection fix
  2011-04-28 13:43             ` Jan Glauber
@ 2011-04-29  4:41               ` Rusty Russell
  2011-04-29 16:35                 ` Jan Glauber
  0 siblings, 1 reply; 12+ messages in thread
From: Rusty Russell @ 2011-04-29  4:41 UTC (permalink / raw)
  To: Jan Glauber
  Cc: Christoph Hellwig, linux-kernel, castet.matthieu, sliakh.lkml,
	jiang, mingo

On Thu, 28 Apr 2011 15:43:21 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> On Thu, Apr 28, 2011 at 09:06:39PM +0930, Rusty Russell wrote:
> > On Thu, 28 Apr 2011 12:08:20 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> > > How about this?
> > > 
> > > To be honest I don't like the inverse naming like in unset no-execute
> > > too much, it makes me feel dizzy. But I wanted to keep the changes
> > > minimal.
> > 
> > Yes, it should probably just be called protect_module_pages and
> > unprotect_module_pages.  The current names provide far too much
> > information.
> > 
> > But going back a bit, how did we end up with a NULL mod->module_init and
> > yet module->init_text_size, mod->init_size or mod->init_ro_size
> > non-zero?
> 
> printk'ing this reveals that mod->init_ro_size is not 0 but 0x1000.
> Therefore the first page was modified.
> 
> Looks like init_ro_size is missing the reset to zero at the end of the init_module
> syscall. Next patch ? ;-

Yes, that seems like a much cleaner and clearer fix to me...

Thanks,
Rusty.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Undoing module RONX protection fix
  2011-04-29  4:41               ` Rusty Russell
@ 2011-04-29 16:35                 ` Jan Glauber
  2011-04-30  6:13                   ` Rusty Russell
  0 siblings, 1 reply; 12+ messages in thread
From: Jan Glauber @ 2011-04-29 16:35 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Christoph Hellwig, linux-kernel, castet.matthieu, sliakh.lkml,
	jiang, mingo

On Fri, Apr 29, 2011 at 02:11:16PM +0930, Rusty Russell wrote:
> On Thu, 28 Apr 2011 15:43:21 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> > On Thu, Apr 28, 2011 at 09:06:39PM +0930, Rusty Russell wrote:
> > > On Thu, 28 Apr 2011 12:08:20 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> > > > How about this?
> > > > 
> > > > To be honest I don't like the inverse naming like in unset no-execute
> > > > too much, it makes me feel dizzy. But I wanted to keep the changes
> > > > minimal.
> > > 
> > > Yes, it should probably just be called protect_module_pages and
> > > unprotect_module_pages.  The current names provide far too much
> > > information.
> > > 
> > > But going back a bit, how did we end up with a NULL mod->module_init and
> > > yet module->init_text_size, mod->init_size or mod->init_ro_size
> > > non-zero?
> > 
> > printk'ing this reveals that mod->init_ro_size is not 0 but 0x1000.
> > Therefore the first page was modified.
> > 
> > Looks like init_ro_size is missing the reset to zero at the end of the init_module
> > syscall. Next patch ? ;-
> 
> Yes, that seems like a much cleaner and clearer fix to me...

Rusty, I'm not sure if I should resend a merged patch or not, going for the
later so you can apply on top of what you might have. If you would appreciate a
merged patch more please let me know...

Cheers,
Jan
------

Reset mod->init_ro_size to zero after the init part of a module is unloaded. 
That makes the check if a module part exists in the unprotect functions
superfluous so they can be removed.

Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
---
 kernel/module.c |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1609,8 +1609,6 @@ static void set_section_ro_nx(void *base
 
 static void unset_module_core_ro_nx(struct module *mod)
 {
-	if (mod->module_core == NULL)
-		return;
 	set_page_attributes(mod->module_core + mod->core_text_size,
 		mod->module_core + mod->core_size,
 		set_memory_x);
@@ -1621,8 +1619,6 @@ static void unset_module_core_ro_nx(stru
 
 static void unset_module_init_ro_nx(struct module *mod)
 {
-	if (mod->module_init == NULL)
-		return;
 	set_page_attributes(mod->module_init + mod->init_text_size,
 		mod->module_init + mod->init_size,
 		set_memory_x);
@@ -2941,6 +2937,7 @@ SYSCALL_DEFINE3(init_module, void __user
 	module_free(mod, mod->module_init);
 	mod->module_init = NULL;
 	mod->init_size = 0;
+	mod->init_ro_size = 0;
 	mod->init_text_size = 0;
 	mutex_unlock(&module_mutex);
 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Undoing module RONX protection fix
  2011-04-29 16:35                 ` Jan Glauber
@ 2011-04-30  6:13                   ` Rusty Russell
  0 siblings, 0 replies; 12+ messages in thread
From: Rusty Russell @ 2011-04-30  6:13 UTC (permalink / raw)
  To: Jan Glauber
  Cc: Christoph Hellwig, linux-kernel, castet.matthieu, sliakh.lkml,
	jiang, mingo

On Fri, 29 Apr 2011 18:35:00 +0200, Jan Glauber <jang@linux.vnet.ibm.com> wrote:
> Rusty, I'm not sure if I should resend a merged patch or not, going for the
> later so you can apply on top of what you might have. If you would appreciate a
> merged patch more please let me know...

Yeah, it was a bit messy.  I applied the third chunk of this, shuffled
it to the top, threw away the initial fix and fixed up the successors (I
use patch queues, so editing the diffs for this stuff makes it pretty
easy).

I've appended all three patches that resulted below (there's nothing
new, just so you can see the final presentation).

Thanks!
Rusty.
PS.  Don't let that stop you from doing more cleanups as discussed
though :)

From: Jan Glauber <jang@linux.vnet.ibm.com>
Subject: module: zero mod->init_ro_size after init is freed.

Reset mod->init_ro_size to zero after the init part of a module is unloaded. 
Otherwise we need to check if module->init is NULL in the unprotect functions
in the next patch.

Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 kernel/module.c |    1 +
 1 file changed, 1 insertion(+)

--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2941,6 +2937,7 @@ SYSCALL_DEFINE3(init_module, void __user
 	module_free(mod, mod->module_init);
 	mod->module_init = NULL;
 	mod->init_size = 0;
+	mod->init_ro_size = 0;
 	mod->init_text_size = 0;
 	mutex_unlock(&module_mutex);
 
Subject: module: undo module RONX protection correctly.
From: Jan Glauber <jang@linux.vnet.ibm.com>

While debugging I stumbled over two problems in the code that protects module
pages.

First issue is that disabling the protection before freeing init or unload of
a module is not symmetric with the enablement. For instance, if pages are set
to RO the page range from module_core to module_core + core_ro_size is
protected. If a module is unloaded the page range from module_core to
module_core + core_size is set back to RW.
So pages that were not set to RO are also changed to RW.
This is not critical but IMHO it should be symmetric.

Second issue is that while set_memory_rw & set_memory_ro are used for
RO/RW changes only set_memory_nx is involved for NX/X. One would await that
the inverse function is called when the NX protection should be removed,
which is not the case here, unless I'm missing something.

Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 arch/s390/include/asm/cacheflush.h |    1 +
 arch/s390/mm/pageattr.c            |    5 +++++
 kernel/module.c                    |   25 +++++++++++++------------
 3 files changed, 19 insertions(+), 12 deletions(-)

--- a/arch/s390/include/asm/cacheflush.h
+++ b/arch/s390/include/asm/cacheflush.h
@@ -11,5 +11,6 @@ void kernel_map_pages(struct page *page,
 int set_memory_ro(unsigned long addr, int numpages);
 int set_memory_rw(unsigned long addr, int numpages);
 int set_memory_nx(unsigned long addr, int numpages);
+int set_memory_x(unsigned long addr, int numpages);
 
 #endif /* _S390_CACHEFLUSH_H */
--- a/arch/s390/mm/pageattr.c
+++ b/arch/s390/mm/pageattr.c
@@ -54,3 +54,8 @@ int set_memory_nx(unsigned long addr, in
 	return 0;
 }
 EXPORT_SYMBOL_GPL(set_memory_nx);
+
+int set_memory_x(unsigned long addr, int numpages)
+{
+	return 0;
+}
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1607,22 +1607,23 @@ static void set_section_ro_nx(void *base
 	}
 }
 
-/* Setting memory back to RW+NX before releasing it */
+/* Setting memory back to W+X before releasing it */
 void unset_section_ro_nx(struct module *mod, void *module_region)
 {
-	unsigned long total_pages;
-
 	if (mod->module_core == module_region) {
-		/* Set core as NX+RW */
-		total_pages = MOD_NUMBER_OF_PAGES(mod->module_core, mod->core_size);
-		set_memory_nx((unsigned long)mod->module_core, total_pages);
-		set_memory_rw((unsigned long)mod->module_core, total_pages);
-
+		set_page_attributes(mod->module_core + mod->core_text_size,
+			mod->module_core + mod->core_size,
+			set_memory_x);
+		set_page_attributes(mod->module_core,
+			mod->module_core + mod->core_ro_size,
+			set_memory_rw);
 	} else if (mod->module_init == module_region) {
-		/* Set init as NX+RW */
-		total_pages = MOD_NUMBER_OF_PAGES(mod->module_init, mod->init_size);
-		set_memory_nx((unsigned long)mod->module_init, total_pages);
-		set_memory_rw((unsigned long)mod->module_init, total_pages);
+		set_page_attributes(mod->module_init + mod->init_text_size,
+			mod->module_init + mod->init_size,
+			set_memory_x);
+		set_page_attributes(mod->module_init,
+			mod->module_init + mod->init_ro_size,
+			set_memory_rw);
 	}
 }
 

Subject: module: split unset_section_ro_nx function.
From: Jan Glauber <jang@linux.vnet.ibm.com>

Split the unprotect function into a function per section to make
the code more readable and add the missing static declaration.

Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 kernel/module.c |   43 ++++++++++++++++++++++---------------------
 1 file changed, 22 insertions(+), 21 deletions(-)

diff --git a/kernel/module.c b/kernel/module.c
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1607,24 +1607,24 @@ static void set_section_ro_nx(void *base
 	}
 }
 
-/* Setting memory back to W+X before releasing it */
-void unset_section_ro_nx(struct module *mod, void *module_region)
+static void unset_module_core_ro_nx(struct module *mod)
 {
-	if (mod->module_core == module_region) {
-		set_page_attributes(mod->module_core + mod->core_text_size,
-			mod->module_core + mod->core_size,
-			set_memory_x);
-		set_page_attributes(mod->module_core,
-			mod->module_core + mod->core_ro_size,
-			set_memory_rw);
-	} else if (mod->module_init == module_region) {
-		set_page_attributes(mod->module_init + mod->init_text_size,
-			mod->module_init + mod->init_size,
-			set_memory_x);
-		set_page_attributes(mod->module_init,
-			mod->module_init + mod->init_ro_size,
-			set_memory_rw);
-	}
+	set_page_attributes(mod->module_core + mod->core_text_size,
+		mod->module_core + mod->core_size,
+		set_memory_x);
+	set_page_attributes(mod->module_core,
+		mod->module_core + mod->core_ro_size,
+		set_memory_rw);
+}
+
+static void unset_module_init_ro_nx(struct module *mod)
+{
+	set_page_attributes(mod->module_init + mod->init_text_size,
+		mod->module_init + mod->init_size,
+		set_memory_x);
+	set_page_attributes(mod->module_init,
+		mod->module_init + mod->init_ro_size,
+		set_memory_rw);
 }
 
 /* Iterate through all modules and set each module's text as RW */
@@ -1670,7 +1670,8 @@ void set_all_modules_text_ro(void)
 }
 #else
 static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { }
-static inline void unset_section_ro_nx(struct module *mod, void *module_region) { }
+static void unset_module_core_ro_nx(struct module *mod) { }
+static void unset_module_init_ro_nx(struct module *mod) { }
 #endif
 
 /* Free a module, remove from lists, etc. */
@@ -1697,7 +1698,7 @@ static void free_module(struct module *m
 	destroy_params(mod->kp, mod->num_kp);
 
 	/* This may be NULL, but that's OK */
-	unset_section_ro_nx(mod, mod->module_init);
+	unset_module_init_ro_nx(mod);
 	module_free(mod, mod->module_init);
 	kfree(mod->args);
 	percpu_modfree(mod);
@@ -1706,7 +1707,7 @@ static void free_module(struct module *m
 	lockdep_free_key_range(mod->module_core, mod->core_size);
 
 	/* Finally, free the core (containing the module structure) */
-	unset_section_ro_nx(mod, mod->module_core);
+	unset_module_core_ro_nx(mod);
 	module_free(mod, mod->module_core);
 
 #ifdef CONFIG_MPU
@@ -2932,7 +2933,7 @@ SYSCALL_DEFINE3(init_module, void __user
 	mod->symtab = mod->core_symtab;
 	mod->strtab = mod->core_strtab;
 #endif
-	unset_section_ro_nx(mod, mod->module_init);
+	unset_module_init_ro_nx(mod);
 	module_free(mod, mod->module_init);
 	mod->module_init = NULL;
 	mod->init_size = 0;

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-04-30  6:13 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-04-18  9:23 Undoing module RONX protection Jan Glauber
2011-04-18  9:28 ` Christoph Hellwig
2011-04-18 10:43   ` Rusty Russell
2011-04-21 14:19     ` Jan Glauber
2011-04-27  5:12       ` Undoing module RONX protection fix Rusty Russell
2011-04-28 10:08         ` Jan Glauber
2011-04-28 11:36           ` Rusty Russell
2011-04-28 13:43             ` Jan Glauber
2011-04-29  4:41               ` Rusty Russell
2011-04-29 16:35                 ` Jan Glauber
2011-04-30  6:13                   ` Rusty Russell
2011-04-18 12:40   ` Undoing module RONX protection Jan Glauber

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).