
From: Rusty Russell <rusty@rustcorp.com.au>

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.

kernel_text_address doesn't take any locks, because during an OOPS we don't
want to deadlock.  Rename that to __kernel_text_address, and make
kernel_text_address take the lock.

Signed-off-by: Zwane Mwaikambo <zwane@fsmlabs.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (modified)
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/i386/kernel/traps.c   |    2 +-
 25-akpm/arch/m68k/kernel/traps.c   |    2 +-
 25-akpm/arch/mips/kernel/traps.c   |    2 +-
 25-akpm/arch/parisc/kernel/traps.c |    2 +-
 25-akpm/arch/um/kernel/sysrq.c     |    2 +-
 25-akpm/arch/x86_64/kernel/traps.c |    6 +++---
 25-akpm/include/linux/kernel.h     |    1 +
 25-akpm/include/linux/module.h     |    9 ++++++++-
 25-akpm/kernel/extable.c           |   15 ++++++++++++++-
 25-akpm/kernel/module.c            |   14 +++++++++++++-
 10 files changed, 44 insertions(+), 11 deletions(-)

diff -puN arch/i386/kernel/traps.c~fix-module_text_address-store_stackinfo-race-2 arch/i386/kernel/traps.c
--- 25/arch/i386/kernel/traps.c~fix-module_text_address-store_stackinfo-race-2	2004-06-24 00:37:15.957640048 -0700
+++ 25-akpm/arch/i386/kernel/traps.c	2004-06-24 00:37:15.975637312 -0700
@@ -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");
diff -puN arch/m68k/kernel/traps.c~fix-module_text_address-store_stackinfo-race-2 arch/m68k/kernel/traps.c
--- 25/arch/m68k/kernel/traps.c~fix-module_text_address-store_stackinfo-race-2	2004-06-24 00:37:15.959639744 -0700
+++ 25-akpm/arch/m68k/kernel/traps.c	2004-06-24 00:37:15.976637160 -0700
@@ -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       ");
diff -puN arch/mips/kernel/traps.c~fix-module_text_address-store_stackinfo-race-2 arch/mips/kernel/traps.c
--- 25/arch/mips/kernel/traps.c~fix-module_text_address-store_stackinfo-race-2	2004-06-24 00:37:15.961639440 -0700
+++ 25-akpm/arch/mips/kernel/traps.c	2004-06-24 00:37:15.977637008 -0700
@@ -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);
 		}
diff -puN arch/parisc/kernel/traps.c~fix-module_text_address-store_stackinfo-race-2 arch/parisc/kernel/traps.c
--- 25/arch/parisc/kernel/traps.c~fix-module_text_address-store_stackinfo-race-2	2004-06-24 00:37:15.962639288 -0700
+++ 25-akpm/arch/parisc/kernel/traps.c	2004-06-24 00:37:15.978636856 -0700
@@ -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);
diff -puN arch/um/kernel/sysrq.c~fix-module_text_address-store_stackinfo-race-2 arch/um/kernel/sysrq.c
--- 25/arch/um/kernel/sysrq.c~fix-module_text_address-store_stackinfo-race-2	2004-06-24 00:37:15.964638984 -0700
+++ 25-akpm/arch/um/kernel/sysrq.c	2004-06-24 00:37:15.979636704 -0700
@@ -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);
diff -puN arch/x86_64/kernel/traps.c~fix-module_text_address-store_stackinfo-race-2 arch/x86_64/kernel/traps.c
--- 25/arch/x86_64/kernel/traps.c~fix-module_text_address-store_stackinfo-race-2	2004-06-24 00:37:15.965638832 -0700
+++ 25-akpm/arch/x86_64/kernel/traps.c	2004-06-24 00:37:15.979636704 -0700
@@ -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) { 
diff -puN include/linux/kernel.h~fix-module_text_address-store_stackinfo-race-2 include/linux/kernel.h
--- 25/include/linux/kernel.h~fix-module_text_address-store_stackinfo-race-2	2004-06-24 00:37:15.967638528 -0700
+++ 25-akpm/include/linux/kernel.h	2004-06-24 00:37:15.980636552 -0700
@@ -93,6 +93,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);
 
diff -puN include/linux/module.h~fix-module_text_address-store_stackinfo-race-2 include/linux/module.h
--- 25/include/linux/module.h~fix-module_text_address-store_stackinfo-race-2	2004-06-24 00:37:15.968638376 -0700
+++ 25-akpm/include/linux/module.h	2004-06-24 00:37:15.981636400 -0700
@@ -335,8 +335,9 @@ static inline int module_is_live(struct 
 	return mod->state != MODULE_STATE_GOING;
 }
 
-/* Is this address in a module? */
+/* Is this address in a module? (second is with no locks, for oops) */
 struct module *module_text_address(unsigned long addr);
+struct module *__module_text_address(unsigned long addr);
 
 /* Returns module and fills in value, defined and namebuf, or NULL if
    symnum out of range. */
@@ -462,6 +463,12 @@ static inline struct module *module_text
 	return NULL;
 }
 
+/* Is this address in a module? (don't take a lock, we're oopsing) */
+static inline struct module *__module_text_address(unsigned long addr)
+{
+	return NULL;
+}
+
 /* Get/put a kernel symbol (calls should be symmetric) */
 #define symbol_get(x) ({ extern typeof(x) x __attribute__((weak)); &(x); })
 #define symbol_put(x) do { } while(0)
diff -puN kernel/extable.c~fix-module_text_address-store_stackinfo-race-2 kernel/extable.c
--- 25/kernel/extable.c~fix-module_text_address-store_stackinfo-race-2	2004-06-24 00:37:15.969638224 -0700
+++ 25-akpm/kernel/extable.c	2004-06-24 00:37:15.982636248 -0700
@@ -40,7 +40,7 @@ const struct exception_table_entry *sear
 	return e;
 }
 
-int kernel_text_address(unsigned long addr)
+static int core_kernel_text(unsigned long addr)
 {
 	if (addr >= (unsigned long)_stext &&
 	    addr <= (unsigned long)_etext)
@@ -49,6 +49,19 @@ int kernel_text_address(unsigned long ad
 	if (addr >= (unsigned long)_sinittext &&
 	    addr <= (unsigned long)_einittext)
 		return 1;
+	return 0;
+}
 
+int __kernel_text_address(unsigned long addr)
+{
+	if (core_kernel_text(addr))
+		return 1;
+	return __module_text_address(addr) != NULL;
+}
+
+int kernel_text_address(unsigned long addr)
+{
+	if (core_kernel_text(addr))
+		return 1;
 	return module_text_address(addr) != NULL;
 }
diff -puN kernel/module.c~fix-module_text_address-store_stackinfo-race-2 kernel/module.c
--- 25/kernel/module.c~fix-module_text_address-store_stackinfo-race-2	2004-06-24 00:37:15.971637920 -0700
+++ 25-akpm/kernel/module.c	2004-06-24 00:37:15.983636096 -0700
@@ -2128,7 +2128,7 @@ const struct exception_table_entry *sear
 }
 
 /* Is this a valid kernel address?  We don't grab the lock: we are oopsing. */
-struct module *module_text_address(unsigned long addr)
+struct module *__module_text_address(unsigned long addr)
 {
 	struct module *mod;
 
@@ -2139,6 +2139,18 @@ struct module *module_text_address(unsig
 	return NULL;
 }
 
+struct module *module_text_address(unsigned long addr)
+{
+	struct module *mod;
+	unsigned long flags;
+
+	spin_lock_irqsave(&modlist_lock, flags);
+	mod = __module_text_address(addr);
+	spin_unlock_irqrestore(&modlist_lock, flags);
+
+	return mod;
+}
+
 /* Don't grab lock, we're oopsing. */
 void print_modules(void)
 {
_
