public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH][2.6] Fix module_text_address/store_stackinfo race
@ 2004-06-23  8:02 Zwane Mwaikambo
  2004-06-24  4:24 ` Rusty Russell
  0 siblings, 1 reply; 5+ messages in thread
From: Zwane Mwaikambo @ 2004-06-23  8:02 UTC (permalink / raw)
  To: Linux Kernel; +Cc: Rusty Russell, Andrew Morton, Manfred Spraul

store_stackinfo() does an unlocked module list walk during normal runtime
which opens up a race with the module load/unload code. This can be
triggered by simply unloading and loading a module in a loop with
CONFIG_DEBUG_PAGEALLOC resulting in store_stackinfo() tripping over bad
list pointers.

root@arusha ~ {0:0} Unable to handle kernel paging request at virtual address 00100100
 printing eip:
c013c46e
*pde = 00000000
Oops: 0000 [#1]
PREEMPT SMP DEBUG_PAGEALLOC
Modules linked in: usbserial
CPU:    1
EIP:    0060:[<c013c46e>]    Not tainted
EFLAGS: 00010083   (2.6.7)
EIP is at module_text_address+0x4e/0x70
eax: 001000fc   ebx: d736faec   ecx: 001000fc   edx: 00100100
esi: d736faec   edi: dff2cef8   ebp: dff2ce8c   esp: dff2ce88
ds: 007b   es: 007b   ss: 0068
Process init (pid: 1, threadinfo=dff2c000 task=dff2da60)
Stack: d736fb04 dff2ce98 c0134e16 d736faec dff2ceb4 c0147ecb d736faec 000004f4
       c012b711 d736f000 dfffbc60 dff2cee8 c014ae85 dfffbc60 d736f000 c012b711
       1736f000 c012b711 d736f000 dff0bf78 00000082 d611aa60 00000000 00000002
Call Trace:
 [<c0107675>] show_stack+0x75/0x90
 [<c01077d5>] show_registers+0x125/0x180
 [<c0107966>] die+0xa6/0xd0
 [<c0118538>] do_page_fault+0x1e8/0x535
 [<c01072cd>] error_code+0x2d/0x40
 [<c0134e16>] kernel_text_address+0x36/0x50
 [<c0147ecb>] store_stackinfo+0x7b/0xa0
 [<c014ae85>] kmem_cache_free+0x1a5/0x340
 [<c012b711>] __exit_sighand+0x31/0x40
 [<c0122a1b>] release_task+0xab/0x2c0
 [<c0124dae>] wait_task_zombie+0x1be/0x260
 [<c01252a2>] sys_wait4+0x222/0x270
 [<c0125306>] sys_waitpid+0x16/0x1a
 [<c0106139>] sysenter_past_esp+0x52/0x79

Code: 8b 40 04 8d 74 26 00 81 fa c0 d3 5d c0 75 c3 31 c0 5b 5d c3

Patch against 2.6.7-mm1

 arch/i386/kernel/traps.c   |    2 +-
 arch/m68k/kernel/traps.c   |    2 +-
 arch/mips/kernel/traps.c   |    2 +-
 arch/parisc/kernel/traps.c |    2 +-
 arch/um/kernel/sysrq.c     |    2 +-
 arch/x86_64/kernel/traps.c |    6 +++---
 include/linux/kernel.h     |    1 +
 kernel/extable.c           |   12 ------------
 kernel/module.c            |   28 +++++++++++++++++++++++++++-
 9 files changed, 36 insertions(+), 21 deletions(-)

Signed-off-by: Zwane Mwaikambo <zwane@fsmlabs.com>

Index: linux-2.6.7-mm1/arch/i386/kernel/traps.c
===================================================================
RCS file: /home/cvsroot/linux-2.6.7-mm1/arch/i386/kernel/traps.c,v
retrieving revision 1.1.1.1
diff -u -p -B -r1.1.1.1 traps.c
--- linux-2.6.7-mm1/arch/i386/kernel/traps.c	22 Jun 2004 16:24:54 -0000	1.1.1.1
+++ linux-2.6.7-mm1/arch/i386/kernel/traps.c	23 Jun 2004 07:57:26 -0000
@@ -158,7 +158,7 @@ static void print_context_stack(struct t

 	while (!kstack_end(stack)) {
 		addr = *stack++;
-		if (kernel_text_address(addr)) {
+		if (__kernel_text_address(addr)) {
 			printk(" [<%08lx>]", addr);
 			print_symbol(" %s", addr);
 			printk("\n");
Index: linux-2.6.7-mm1/arch/m68k/kernel/traps.c
===================================================================
RCS file: /home/cvsroot/linux-2.6.7-mm1/arch/m68k/kernel/traps.c,v
retrieving revision 1.1.1.1
diff -u -p -B -r1.1.1.1 traps.c
--- linux-2.6.7-mm1/arch/m68k/kernel/traps.c	22 Jun 2004 16:24:57 -0000	1.1.1.1
+++ linux-2.6.7-mm1/arch/m68k/kernel/traps.c	23 Jun 2004 07:57:10 -0000
@@ -911,7 +911,7 @@ void show_trace(unsigned long *stack)
 		 * down the cause of the crash will be able to figure
 		 * out the call path that was taken.
 		 */
-		if (kernel_text_address(addr)) {
+		if (__kernel_text_address(addr)) {
 #ifndef CONFIG_KALLSYMS
 			if (i % 5 == 0)
 				printk("\n       ");
Index: linux-2.6.7-mm1/arch/mips/kernel/traps.c
===================================================================
RCS file: /home/cvsroot/linux-2.6.7-mm1/arch/mips/kernel/traps.c,v
retrieving revision 1.1.1.1
diff -u -p -B -r1.1.1.1 traps.c
--- linux-2.6.7-mm1/arch/mips/kernel/traps.c	22 Jun 2004 16:24:56 -0000	1.1.1.1
+++ linux-2.6.7-mm1/arch/mips/kernel/traps.c	23 Jun 2004 07:57:10 -0000
@@ -118,7 +118,7 @@ void show_trace(struct task_struct *task
 #endif
 	while (!kstack_end(stack)) {
 		addr = *stack++;
-		if (kernel_text_address(addr)) {
+		if (__kernel_text_address(addr)) {
 			printk(" [<%0*lx>] ", field, addr);
 			print_symbol("%s\n", addr);
 		}
Index: linux-2.6.7-mm1/arch/parisc/kernel/traps.c
===================================================================
RCS file: /home/cvsroot/linux-2.6.7-mm1/arch/parisc/kernel/traps.c,v
retrieving revision 1.1.1.1
diff -u -p -B -r1.1.1.1 traps.c
--- linux-2.6.7-mm1/arch/parisc/kernel/traps.c	22 Jun 2004 16:24:59 -0000	1.1.1.1
+++ linux-2.6.7-mm1/arch/parisc/kernel/traps.c	23 Jun 2004 07:57:10 -0000
@@ -188,7 +188,7 @@ void show_trace(struct task_struct *task
 		 * down the cause of the crash will be able to figure
 		 * out the call path that was taken.
 		 */
-		if (kernel_text_address(addr)) {
+		if (__kernel_text_address(addr)) {
 			printk(" [<" RFMT ">] ", addr);
 #ifdef CONFIG_KALLSYMS
 			print_symbol("%s\n", addr);
Index: linux-2.6.7-mm1/arch/um/kernel/sysrq.c
===================================================================
RCS file: /home/cvsroot/linux-2.6.7-mm1/arch/um/kernel/sysrq.c,v
retrieving revision 1.1.1.1
diff -u -p -B -r1.1.1.1 sysrq.c
--- linux-2.6.7-mm1/arch/um/kernel/sysrq.c	22 Jun 2004 16:24:55 -0000	1.1.1.1
+++ linux-2.6.7-mm1/arch/um/kernel/sysrq.c	23 Jun 2004 07:57:10 -0000
@@ -23,7 +23,7 @@ void show_trace(unsigned long * stack)
         i = 1;
         while (((long) stack & (THREAD_SIZE-1)) != 0) {
                 addr = *stack++;
-		if (kernel_text_address(addr)) {
+		if (__kernel_text_address(addr)) {
 			if (i && ((i % 6) == 0))
 				printk("\n   ");
 			printk("[<%08lx>] ", addr);
Index: linux-2.6.7-mm1/arch/x86_64/kernel/traps.c
===================================================================
RCS file: /home/cvsroot/linux-2.6.7-mm1/arch/x86_64/kernel/traps.c,v
retrieving revision 1.1.1.1
diff -u -p -B -r1.1.1.1 traps.c
--- linux-2.6.7-mm1/arch/x86_64/kernel/traps.c	22 Jun 2004 16:24:59 -0000	1.1.1.1
+++ linux-2.6.7-mm1/arch/x86_64/kernel/traps.c	23 Jun 2004 07:57:10 -0000
@@ -143,7 +143,7 @@ void show_trace(unsigned long *stack)
 	if (estack_end) {
 		while (stack < estack_end) {
 			addr = *stack++;
-			if (kernel_text_address(addr)) {
+			if (__kernel_text_address(addr)) {
 				i += printk_address(addr);
 				i += printk(" ");
 				if (i > 50) {
@@ -172,7 +172,7 @@ void show_trace(unsigned long *stack)
 			 * down the cause of the crash will be able to figure
 			 * out the call path that was taken.
 			 */
-			 if (kernel_text_address(addr)) {
+			 if (__kernel_text_address(addr)) {
 				 i += printk_address(addr);
 				 i += printk(" ");
 				 if (i > 50) {
@@ -188,7 +188,7 @@ void show_trace(unsigned long *stack)

 	while (((long) stack & (THREAD_SIZE-1)) != 0) {
 		addr = *stack++;
-		if (kernel_text_address(addr)) {
+		if (__kernel_text_address(addr)) {
 			i += printk_address(addr);
 			i += printk(" ");
 			if (i > 50) {
Index: linux-2.6.7-mm1/include/linux/kernel.h
===================================================================
RCS file: /home/cvsroot/linux-2.6.7-mm1/include/linux/kernel.h,v
retrieving revision 1.1.1.1
diff -u -p -B -r1.1.1.1 kernel.h
--- linux-2.6.7-mm1/include/linux/kernel.h	22 Jun 2004 16:24:59 -0000	1.1.1.1
+++ linux-2.6.7-mm1/include/linux/kernel.h	23 Jun 2004 07:57:10 -0000
@@ -88,6 +88,7 @@ extern int get_option(char **str, int *p
 extern char *get_options(const char *str, int nints, int *ints);
 extern unsigned long long memparse(char *ptr, char **retptr);

+extern int __kernel_text_address(unsigned long addr);
 extern int kernel_text_address(unsigned long addr);
 extern int session_of_pgrp(int pgrp);

Index: linux-2.6.7-mm1/kernel/extable.c
===================================================================
RCS file: /home/cvsroot/linux-2.6.7-mm1/kernel/extable.c,v
retrieving revision 1.1.1.1
diff -u -p -B -r1.1.1.1 extable.c
--- linux-2.6.7-mm1/kernel/extable.c	22 Jun 2004 16:25:12 -0000	1.1.1.1
+++ linux-2.6.7-mm1/kernel/extable.c	23 Jun 2004 07:57:10 -0000
@@ -40,15 +40,3 @@ const struct exception_table_entry *sear
 	return e;
 }

-int kernel_text_address(unsigned long addr)
-{
-	if (addr >= (unsigned long)_stext &&
-	    addr <= (unsigned long)_etext)
-		return 1;
-
-	if (addr >= (unsigned long)_sinittext &&
-	    addr <= (unsigned long)_einittext)
-		return 1;
-
-	return module_text_address(addr) != NULL;
-}
Index: linux-2.6.7-mm1/kernel/module.c
===================================================================
RCS file: /home/cvsroot/linux-2.6.7-mm1/kernel/module.c,v
retrieving revision 1.1.1.1
diff -u -p -B -r1.1.1.1 module.c
--- linux-2.6.7-mm1/kernel/module.c	22 Jun 2004 16:25:12 -0000	1.1.1.1
+++ linux-2.6.7-mm1/kernel/module.c	23 Jun 2004 07:57:10 -0000
@@ -35,6 +35,7 @@
 #include <linux/notifier.h>
 #include <linux/stop_machine.h>
 #include <asm/uaccess.h>
+#include <asm/sections.h>
 #include <asm/semaphore.h>
 #include <asm/cacheflush.h>

@@ -670,7 +671,7 @@ void symbol_put_addr(void *addr)
 	unsigned long flags;

 	spin_lock_irqsave(&modlist_lock, flags);
-	if (!kernel_text_address((unsigned long)addr))
+	if (!__kernel_text_address((unsigned long)addr))
 		BUG();

 	module_put(module_text_address((unsigned long)addr));
@@ -678,6 +679,31 @@ void symbol_put_addr(void *addr)
 }
 EXPORT_SYMBOL_GPL(symbol_put_addr);

+int __kernel_text_address(unsigned long addr)
+{
+	if (addr >= (unsigned long)_stext &&
+	    addr <= (unsigned long)_etext)
+		return 1;
+
+	if (addr >= (unsigned long)_sinittext &&
+	    addr <= (unsigned long)_einittext)
+		return 1;
+
+	return module_text_address(addr) != NULL;
+}
+
+int kernel_text_address(unsigned long addr)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&modlist_lock, flags);
+	ret = __kernel_text_address(addr);
+	spin_unlock_irqrestore(&modlist_lock, flags);
+
+	return ret;
+}
+
 static int refcnt_get_fn(char *buffer, struct kernel_param *kp)
 {
 	struct module *mod = container_of(kp, struct module, refcnt_param);

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

end of thread, other threads:[~2004-06-24 15:24 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-06-23  8:02 [PATCH][2.6] Fix module_text_address/store_stackinfo race Zwane Mwaikambo
2004-06-24  4:24 ` Rusty Russell
2004-06-24  4:42   ` Zwane Mwaikambo
2004-06-24  7:18     ` Rusty Russell
2004-06-24 15:26       ` Zwane Mwaikambo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox