* [PATCH 1/3] module_arch_freeing_init(): new hook for archs before module->module_init freed.
2015-01-08 0:58 [PATCH 0/3] Module load failure race fix Rusty Russell
@ 2015-01-08 0:58 ` Rusty Russell
2015-01-08 7:55 ` Hans-Christian Egtvedt
2015-01-13 21:11 ` Helge Deller
2015-01-08 0:58 ` [PATCH 2/3] module: remove mod arg from module_free, rename module_memfree() Rusty Russell
2015-01-08 0:58 ` [PATCH 3/3] module: fix race in kallsyms resolution during module load success Rusty Russell
2 siblings, 2 replies; 6+ messages in thread
From: Rusty Russell @ 2015-01-08 0:58 UTC (permalink / raw)
To: linux-kernel
Cc: Rusty Russell, Chris Metcalf, Haavard Skinnemoen,
Hans-Christian Egtvedt, Tony Luck, Fenghua Yu,
James E.J. Bottomley, Helge Deller, Martin Schwidefsky,
Heiko Carstens, linux-ia64, linux-parisc, linux-s390
Archs have been abusing module_free() to clean up their arch-specific
allocations. Since module_free() is also (ab)used by BPF and trace code,
let's keep it to simple allocations, and provide a hook called before
that.
This means that avr32, ia64, parisc and s390 no longer need to implement
their own module_free() at all. avr32 doesn't need module_finalize()
either.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: Chris Metcalf <cmetcalf@ezchip.com>
Cc: Haavard Skinnemoen <hskinnemoen@gmail.com>
Cc: Hans-Christian Egtvedt <egtvedt@samfundet.no>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
Cc: Helge Deller <deller@gmx.de>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: linux-kernel@vger.kernel.org
Cc: linux-ia64@vger.kernel.org
Cc: linux-parisc@vger.kernel.org
Cc: linux-s390@vger.kernel.org
---
arch/avr32/kernel/module.c | 13 +------------
arch/ia64/kernel/module.c | 6 ++----
arch/parisc/kernel/module.c | 6 +-----
arch/s390/kernel/module.c | 10 +++-------
arch/tile/kernel/module.c | 2 +-
include/linux/moduleloader.h | 2 ++
kernel/module.c | 7 +++++++
7 files changed, 17 insertions(+), 29 deletions(-)
diff --git a/arch/avr32/kernel/module.c b/arch/avr32/kernel/module.c
index 2c9412908024..164efa009e5b 100644
--- a/arch/avr32/kernel/module.c
+++ b/arch/avr32/kernel/module.c
@@ -19,12 +19,10 @@
#include <linux/moduleloader.h>
#include <linux/vmalloc.h>
-void module_free(struct module *mod, void *module_region)
+void module_arch_freeing_init(struct module *mod)
{
vfree(mod->arch.syminfo);
mod->arch.syminfo = NULL;
-
- vfree(module_region);
}
static inline int check_rela(Elf32_Rela *rela, struct module *module,
@@ -291,12 +289,3 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
return ret;
}
-
-int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
- struct module *module)
-{
- vfree(module->arch.syminfo);
- module->arch.syminfo = NULL;
-
- return 0;
-}
diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c
index 24603be24c14..29754aae5177 100644
--- a/arch/ia64/kernel/module.c
+++ b/arch/ia64/kernel/module.c
@@ -305,14 +305,12 @@ plt_target (struct plt_entry *plt)
#endif /* !USE_BRL */
void
-module_free (struct module *mod, void *module_region)
+module_arch_freeing_init (struct module *mod)
{
- if (mod && mod->arch.init_unw_table &&
- module_region == mod->module_init) {
+ if (mod->arch.init_unw_table) {
unw_remove_unwind_table(mod->arch.init_unw_table);
mod->arch.init_unw_table = NULL;
}
- vfree(module_region);
}
/* Have we already seen one of these relocations? */
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
index 50dfafc3f2c1..5822e8e200e6 100644
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -298,14 +298,10 @@ static inline unsigned long count_stubs(const Elf_Rela *rela, unsigned long n)
}
#endif
-
-/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
+void module_arch_freeing_init(struct module *mod)
{
kfree(mod->arch.section);
mod->arch.section = NULL;
-
- vfree(module_region);
}
/* Additional bytes needed in front of individual sections */
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index b89b59158b95..409d152585be 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -55,14 +55,10 @@ void *module_alloc(unsigned long size)
}
#endif
-/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
+void module_arch_freeing_init(struct module *mod)
{
- if (mod) {
- vfree(mod->arch.syminfo);
- mod->arch.syminfo = NULL;
- }
- vfree(module_region);
+ vfree(mod->arch.syminfo);
+ mod->arch.syminfo = NULL;
}
static void check_rela(Elf_Rela *rela, struct module *me)
diff --git a/arch/tile/kernel/module.c b/arch/tile/kernel/module.c
index 96447c9160a0..62a597e810d6 100644
--- a/arch/tile/kernel/module.c
+++ b/arch/tile/kernel/module.c
@@ -83,7 +83,7 @@ void module_free(struct module *mod, void *module_region)
0, 0, 0, NULL, NULL, 0);
/*
- * FIXME: If module_region == mod->module_init, trim exception
+ * FIXME: Add module_arch_freeing_init to trim exception
* table entries.
*/
}
diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h
index 7eeb9bbfb816..054eac853090 100644
--- a/include/linux/moduleloader.h
+++ b/include/linux/moduleloader.h
@@ -82,4 +82,6 @@ int module_finalize(const Elf_Ehdr *hdr,
/* Any cleanup needed when module leaves. */
void module_arch_cleanup(struct module *mod);
+/* Any cleanup before freeing mod->module_init */
+void module_arch_freeing_init(struct module *mod);
#endif
diff --git a/kernel/module.c b/kernel/module.c
index 3965511ae133..68be0b1f9e7f 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1804,6 +1804,10 @@ void __weak module_arch_cleanup(struct module *mod)
{
}
+void __weak module_arch_freeing_init(struct module *mod)
+{
+}
+
/* Free a module, remove from lists, etc. */
static void free_module(struct module *mod)
{
@@ -1841,6 +1845,7 @@ static void free_module(struct module *mod)
/* This may be NULL, but that's OK */
unset_module_init_ro_nx(mod);
+ module_arch_freeing_init(mod);
module_free(mod, mod->module_init);
kfree(mod->args);
percpu_modfree(mod);
@@ -2930,6 +2935,7 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
static void module_deallocate(struct module *mod, struct load_info *info)
{
percpu_modfree(mod);
+ module_arch_freeing_init(mod);
module_free(mod, mod->module_init);
module_free(mod, mod->module_core);
}
@@ -3055,6 +3061,7 @@ static int do_init_module(struct module *mod)
mod->strtab = mod->core_strtab;
#endif
unset_module_init_ro_nx(mod);
+ module_arch_freeing_init(mod);
module_free(mod, mod->module_init);
mod->module_init = NULL;
mod->init_size = 0;
--
2.1.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 1/3] module_arch_freeing_init(): new hook for archs before module->module_init freed.
2015-01-08 0:58 ` [PATCH 1/3] module_arch_freeing_init(): new hook for archs before module->module_init freed Rusty Russell
@ 2015-01-08 7:55 ` Hans-Christian Egtvedt
2015-01-13 21:11 ` Helge Deller
1 sibling, 0 replies; 6+ messages in thread
From: Hans-Christian Egtvedt @ 2015-01-08 7:55 UTC (permalink / raw)
To: Rusty Russell
Cc: linux-kernel, Chris Metcalf, Haavard Skinnemoen, Tony Luck,
Fenghua Yu, James E.J. Bottomley, Helge Deller,
Martin Schwidefsky, Heiko Carstens, linux-ia64, linux-parisc,
linux-s390
Around Thu 08 Jan 2015 11:28:05 +1030 or thereabout, Rusty Russell wrote:
> Archs have been abusing module_free() to clean up their arch-specific
> allocations. Since module_free() is also (ab)used by BPF and trace code,
> let's keep it to simple allocations, and provide a hook called before
> that.
>
> This means that avr32, ia64, parisc and s390 no longer need to implement
> their own module_free() at all. avr32 doesn't need module_finalize()
> either.
At a glance it looks sane.
> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
> Cc: Chris Metcalf <cmetcalf@ezchip.com>
> Cc: Haavard Skinnemoen <hskinnemoen@gmail.com>
> Cc: Hans-Christian Egtvedt <egtvedt@samfundet.no>
> Cc: Tony Luck <tony.luck@intel.com>
> Cc: Fenghua Yu <fenghua.yu@intel.com>
> Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
> Cc: Helge Deller <deller@gmx.de>
> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
> Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
> Cc: linux-kernel@vger.kernel.org
> Cc: linux-ia64@vger.kernel.org
> Cc: linux-parisc@vger.kernel.org
> Cc: linux-s390@vger.kernel.org
Acked-by: Hans-Christian Egtvedt <egtvedt@samfundet.no>
> ---
> arch/avr32/kernel/module.c | 13 +------------
> arch/ia64/kernel/module.c | 6 ++----
> arch/parisc/kernel/module.c | 6 +-----
> arch/s390/kernel/module.c | 10 +++-------
> arch/tile/kernel/module.c | 2 +-
> include/linux/moduleloader.h | 2 ++
> kernel/module.c | 7 +++++++
> 7 files changed, 17 insertions(+), 29 deletions(-)
<snipp diff>
--
HcE
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] module_arch_freeing_init(): new hook for archs before module->module_init freed.
2015-01-08 0:58 ` [PATCH 1/3] module_arch_freeing_init(): new hook for archs before module->module_init freed Rusty Russell
2015-01-08 7:55 ` Hans-Christian Egtvedt
@ 2015-01-13 21:11 ` Helge Deller
1 sibling, 0 replies; 6+ messages in thread
From: Helge Deller @ 2015-01-13 21:11 UTC (permalink / raw)
To: Rusty Russell, linux-kernel
Cc: Chris Metcalf, Haavard Skinnemoen, Hans-Christian Egtvedt,
Tony Luck, Fenghua Yu, James E.J. Bottomley, Martin Schwidefsky,
Heiko Carstens, linux-ia64, linux-parisc, linux-s390
On 08.01.2015 01:58, Rusty Russell wrote:
> Archs have been abusing module_free() to clean up their arch-specific
> allocations. Since module_free() is also (ab)used by BPF and trace code,
> let's keep it to simple allocations, and provide a hook called before
> that.
>
> This means that avr32, ia64, parisc and s390 no longer need to implement
> their own module_free() at all. avr32 doesn't need module_finalize()
> either.
>
> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
> Cc: Chris Metcalf <cmetcalf@ezchip.com>
> Cc: Haavard Skinnemoen <hskinnemoen@gmail.com>
> Cc: Hans-Christian Egtvedt <egtvedt@samfundet.no>
> Cc: Tony Luck <tony.luck@intel.com>
> Cc: Fenghua Yu <fenghua.yu@intel.com>
> Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
> Cc: Helge Deller <deller@gmx.de>
> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
> Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
> Cc: linux-kernel@vger.kernel.org
> Cc: linux-ia64@vger.kernel.org
> Cc: linux-parisc@vger.kernel.org
> Cc: linux-s390@vger.kernel.org
> ---
> arch/avr32/kernel/module.c | 13 +------------
> arch/ia64/kernel/module.c | 6 ++----
> arch/parisc/kernel/module.c | 6 +-----
> arch/s390/kernel/module.c | 10 +++-------
> arch/tile/kernel/module.c | 2 +-
> include/linux/moduleloader.h | 2 ++
> kernel/module.c | 7 +++++++
> 7 files changed, 17 insertions(+), 29 deletions(-)
I successfully tested it on the parisc arch.
Acked-by: Helge Deller <deller@gmx.de>
Thanks!
Helge
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/3] module: remove mod arg from module_free, rename module_memfree().
2015-01-08 0:58 [PATCH 0/3] Module load failure race fix Rusty Russell
2015-01-08 0:58 ` [PATCH 1/3] module_arch_freeing_init(): new hook for archs before module->module_init freed Rusty Russell
@ 2015-01-08 0:58 ` Rusty Russell
2015-01-08 0:58 ` [PATCH 3/3] module: fix race in kallsyms resolution during module load success Rusty Russell
2 siblings, 0 replies; 6+ messages in thread
From: Rusty Russell @ 2015-01-08 0:58 UTC (permalink / raw)
To: linux-kernel
Cc: Rusty Russell, Mikael Starvik, Jesper Nilsson, Ralf Baechle,
Ley Foon Tan, Benjamin Herrenschmidt, Chris Metcalf,
Steven Rostedt, x86, Alexei Starovoitov,
Ananth N Mavinakayanahalli, Anil S Keshavamurthy,
Masami Hiramatsu, linux-cris-kernel, linux-mips, nios2-dev,
linuxppc-dev, sparclinux, netdev
Nothing needs the module pointer any more, and the next patch will
call it from RCU, where the module itself might no longer exist.
Removing the arg is the safest approach.
This just codifies the use of the module_alloc/module_free pattern
which ftrace and bpf use.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: Mikael Starvik <starvik@axis.com>
Cc: Jesper Nilsson <jesper.nilsson@axis.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Ley Foon Tan <lftan@altera.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Chris Metcalf <cmetcalf@ezchip.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: x86@kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: linux-cris-kernel@axis.com
Cc: linux-kernel@vger.kernel.org
Cc: linux-mips@linux-mips.org
Cc: nios2-dev@lists.rocketboards.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: sparclinux@vger.kernel.org
Cc: netdev@vger.kernel.org
---
arch/cris/kernel/module.c | 2 +-
arch/mips/net/bpf_jit.c | 2 +-
arch/nios2/kernel/module.c | 2 +-
arch/powerpc/net/bpf_jit_comp.c | 2 +-
arch/sparc/net/bpf_jit_comp.c | 4 ++--
arch/tile/kernel/module.c | 2 +-
arch/x86/kernel/ftrace.c | 2 +-
include/linux/moduleloader.h | 2 +-
kernel/bpf/core.c | 2 +-
kernel/kprobes.c | 2 +-
kernel/module.c | 14 +++++++-------
11 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/arch/cris/kernel/module.c b/arch/cris/kernel/module.c
index 51123f985eb5..af04cb6b6dc9 100644
--- a/arch/cris/kernel/module.c
+++ b/arch/cris/kernel/module.c
@@ -36,7 +36,7 @@ void *module_alloc(unsigned long size)
}
/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
+void module_memfree(void *module_region)
{
kfree(module_region);
}
diff --git a/arch/mips/net/bpf_jit.c b/arch/mips/net/bpf_jit.c
index 9fd6834a2172..5d6139390bf8 100644
--- a/arch/mips/net/bpf_jit.c
+++ b/arch/mips/net/bpf_jit.c
@@ -1388,7 +1388,7 @@ out:
void bpf_jit_free(struct bpf_prog *fp)
{
if (fp->jited)
- module_free(NULL, fp->bpf_func);
+ module_memfree(fp->bpf_func);
bpf_prog_unlock_free(fp);
}
diff --git a/arch/nios2/kernel/module.c b/arch/nios2/kernel/module.c
index cc924a38f22a..e2e3f13f98d5 100644
--- a/arch/nios2/kernel/module.c
+++ b/arch/nios2/kernel/module.c
@@ -36,7 +36,7 @@ void *module_alloc(unsigned long size)
}
/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
+void module_memfree(void *module_region)
{
kfree(module_region);
}
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index 1ca125b9c226..d1916b577f2c 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -699,7 +699,7 @@ out:
void bpf_jit_free(struct bpf_prog *fp)
{
if (fp->jited)
- module_free(NULL, fp->bpf_func);
+ module_memfree(fp->bpf_func);
bpf_prog_unlock_free(fp);
}
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c
index f33e7c7a3bf7..7931eeeb649a 100644
--- a/arch/sparc/net/bpf_jit_comp.c
+++ b/arch/sparc/net/bpf_jit_comp.c
@@ -776,7 +776,7 @@ cond_branch: f_offset = addrs[i + filter[i].jf];
if (unlikely(proglen + ilen > oldproglen)) {
pr_err("bpb_jit_compile fatal error\n");
kfree(addrs);
- module_free(NULL, image);
+ module_memfree(image);
return;
}
memcpy(image + proglen, temp, ilen);
@@ -822,7 +822,7 @@ out:
void bpf_jit_free(struct bpf_prog *fp)
{
if (fp->jited)
- module_free(NULL, fp->bpf_func);
+ module_memfree(fp->bpf_func);
bpf_prog_unlock_free(fp);
}
diff --git a/arch/tile/kernel/module.c b/arch/tile/kernel/module.c
index 62a597e810d6..2305084c9b93 100644
--- a/arch/tile/kernel/module.c
+++ b/arch/tile/kernel/module.c
@@ -74,7 +74,7 @@ error:
/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
+void module_memfree(void *module_region)
{
vfree(module_region);
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 2142376dc8c6..8b7b0a51e742 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -674,7 +674,7 @@ static inline void *alloc_tramp(unsigned long size)
}
static inline void tramp_free(void *tramp)
{
- module_free(NULL, tramp);
+ module_memfree(tramp);
}
#else
/* Trampolines can only be created if modules are supported */
diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h
index 054eac853090..f7556261fe3c 100644
--- a/include/linux/moduleloader.h
+++ b/include/linux/moduleloader.h
@@ -26,7 +26,7 @@ unsigned int arch_mod_section_prepend(struct module *mod, unsigned int section);
void *module_alloc(unsigned long size);
/* Free memory returned from module_alloc. */
-void module_free(struct module *mod, void *module_region);
+void module_memfree(void *module_region);
/*
* Apply the given relocation to the (simplified) ELF. Return -error
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index d6594e457a25..a64e7a207d2b 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -163,7 +163,7 @@ bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
void bpf_jit_binary_free(struct bpf_binary_header *hdr)
{
- module_free(NULL, hdr);
+ module_memfree(hdr);
}
#endif /* CONFIG_BPF_JIT */
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 06f58309fed2..ee619929cf90 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -127,7 +127,7 @@ static void *alloc_insn_page(void)
static void free_insn_page(void *page)
{
- module_free(NULL, page);
+ module_memfree(page);
}
struct kprobe_insn_cache kprobe_insn_slots = {
diff --git a/kernel/module.c b/kernel/module.c
index 68be0b1f9e7f..1f85fd5c89d3 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1795,7 +1795,7 @@ static void unset_module_core_ro_nx(struct module *mod) { }
static void unset_module_init_ro_nx(struct module *mod) { }
#endif
-void __weak module_free(struct module *mod, void *module_region)
+void __weak module_memfree(void *module_region)
{
vfree(module_region);
}
@@ -1846,7 +1846,7 @@ static void free_module(struct module *mod)
/* This may be NULL, but that's OK */
unset_module_init_ro_nx(mod);
module_arch_freeing_init(mod);
- module_free(mod, mod->module_init);
+ module_memfree(mod->module_init);
kfree(mod->args);
percpu_modfree(mod);
@@ -1855,7 +1855,7 @@ static void free_module(struct module *mod)
/* Finally, free the core (containing the module structure) */
unset_module_core_ro_nx(mod);
- module_free(mod, mod->module_core);
+ module_memfree(mod->module_core);
#ifdef CONFIG_MPU
update_protections(current->mm);
@@ -2790,7 +2790,7 @@ static int move_module(struct module *mod, struct load_info *info)
*/
kmemleak_ignore(ptr);
if (!ptr) {
- module_free(mod, mod->module_core);
+ module_memfree(mod->module_core);
return -ENOMEM;
}
memset(ptr, 0, mod->init_size);
@@ -2936,8 +2936,8 @@ static void module_deallocate(struct module *mod, struct load_info *info)
{
percpu_modfree(mod);
module_arch_freeing_init(mod);
- module_free(mod, mod->module_init);
- module_free(mod, mod->module_core);
+ module_memfree(mod->module_init);
+ module_memfree(mod->module_core);
}
int __weak module_finalize(const Elf_Ehdr *hdr,
@@ -3062,7 +3062,7 @@ static int do_init_module(struct module *mod)
#endif
unset_module_init_ro_nx(mod);
module_arch_freeing_init(mod);
- module_free(mod, mod->module_init);
+ module_memfree(mod->module_init);
mod->module_init = NULL;
mod->init_size = 0;
mod->init_ro_size = 0;
--
2.1.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/3] module: fix race in kallsyms resolution during module load success.
2015-01-08 0:58 [PATCH 0/3] Module load failure race fix Rusty Russell
2015-01-08 0:58 ` [PATCH 1/3] module_arch_freeing_init(): new hook for archs before module->module_init freed Rusty Russell
2015-01-08 0:58 ` [PATCH 2/3] module: remove mod arg from module_free, rename module_memfree() Rusty Russell
@ 2015-01-08 0:58 ` Rusty Russell
2 siblings, 0 replies; 6+ messages in thread
From: Rusty Russell @ 2015-01-08 0:58 UTC (permalink / raw)
To: linux-kernel; +Cc: Rusty Russell
The kallsyms routines (module_symbol_name, lookup_module_* etc) disable
preemption to walk the modules rather than taking the module_mutex:
this is because they are used for symbol resolution during oopses.
This works because there are synchronize_sched() and synchronize_rcu()
in the unload and failure paths. However, there's one case which doesn't
have that: the normal case where module loading succeeds, and we free
the init section.
We don't want a synchronize_rcu() there, because it would slow down
module loading: this bug was introduced in 2009 to speed module
loading in the first place.
Thus, we want to do the free in an RCU callback. We do this in the
simplest possible way by allocating a new rcu_head: if we put it in
the module structure we'd have to worry about that getting freed.
Reported-by: Rui Xiang <rui.xiang@huawei.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
kernel/module.c | 55 ++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 42 insertions(+), 13 deletions(-)
diff --git a/kernel/module.c b/kernel/module.c
index 1f85fd5c89d3..ed4ec9c30bd2 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2989,10 +2989,31 @@ static void do_mod_ctors(struct module *mod)
#endif
}
+/* For freeing module_init on success, in case kallsyms traversing */
+struct mod_initfree {
+ struct rcu_head rcu;
+ void *module_init;
+};
+
+static void do_free_init(struct rcu_head *head)
+{
+ struct mod_initfree *m = container_of(head, struct mod_initfree, rcu);
+ module_memfree(m->module_init);
+ kfree(m);
+}
+
/* This is where the real work happens */
static int do_init_module(struct module *mod)
{
int ret = 0;
+ struct mod_initfree *freeinit;
+
+ freeinit = kmalloc(sizeof(*freeinit), GFP_KERNEL);
+ if (!freeinit) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ freeinit->module_init = mod->module_init;
/*
* We want to find out whether @mod uses async during init. Clear
@@ -3005,18 +3026,7 @@ static int do_init_module(struct module *mod)
if (mod->init != NULL)
ret = do_one_initcall(mod->init);
if (ret < 0) {
- /*
- * Init routine failed: abort. Try to protect us from
- * buggy refcounters.
- */
- mod->state = MODULE_STATE_GOING;
- synchronize_sched();
- module_put(mod);
- blocking_notifier_call_chain(&module_notify_list,
- MODULE_STATE_GOING, mod);
- free_module(mod);
- wake_up_all(&module_wq);
- return ret;
+ goto fail_free_freeinit;
}
if (ret > 0) {
pr_warn("%s: '%s'->init suspiciously returned %d, it should "
@@ -3062,15 +3072,34 @@ static int do_init_module(struct module *mod)
#endif
unset_module_init_ro_nx(mod);
module_arch_freeing_init(mod);
- module_memfree(mod->module_init);
mod->module_init = NULL;
mod->init_size = 0;
mod->init_ro_size = 0;
mod->init_text_size = 0;
+ /*
+ * We want to free module_init, but be aware that kallsyms may be
+ * walking this with preempt disabled. In all the failure paths,
+ * we call synchronize_rcu/synchronize_sched, but we don't want
+ * to slow down the success path, so use actual RCU here.
+ */
+ call_rcu(&freeinit->rcu, do_free_init);
mutex_unlock(&module_mutex);
wake_up_all(&module_wq);
return 0;
+
+fail_free_freeinit:
+ kfree(freeinit);
+fail:
+ /* Try to protect us from buggy refcounters. */
+ mod->state = MODULE_STATE_GOING;
+ synchronize_sched();
+ module_put(mod);
+ blocking_notifier_call_chain(&module_notify_list,
+ MODULE_STATE_GOING, mod);
+ free_module(mod);
+ wake_up_all(&module_wq);
+ return ret;
}
static int may_init_module(void)
--
2.1.0
^ permalink raw reply related [flat|nested] 6+ messages in thread