2004-06-23 08:00:31

by Zwane Mwaikambo

[permalink] [raw]
Subject: [PATCH][2.6] Fix module_text_address/store_stackinfo race

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 <[email protected]>

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);


2004-06-24 04:25:12

by Rusty Russell

[permalink] [raw]
Subject: Re: [PATCH][2.6] Fix module_text_address/store_stackinfo race

On Wed, 2004-06-23 at 18:02, Zwane Mwaikambo wrote:
> 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.

Hmmm...

You can't move kernel_text_address into module.c, since it isn't
compiled for CONFIG_MODULES=n.

I don't really like debug code messing with this, but you might be right
about changing it to __kernel_text_address().

Rusty.
--
Anyone who quotes me in their signature is an idiot -- Rusty Russell

2004-06-24 04:39:54

by Zwane Mwaikambo

[permalink] [raw]
Subject: Re: [PATCH][2.6] Fix module_text_address/store_stackinfo race

On Thu, 24 Jun 2004, Rusty Russell wrote:

> On Wed, 2004-06-23 at 18:02, Zwane Mwaikambo wrote:
> > 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.
>
> Hmmm...
>
> You can't move kernel_text_address into module.c, since it isn't
> compiled for CONFIG_MODULES=n.

Good point, how about if i make modlist_lock a global?

2004-06-24 07:19:19

by Rusty Russell

[permalink] [raw]
Subject: Re: [PATCH][2.6] Fix module_text_address/store_stackinfo race

On Thu, 2004-06-24 at 14:42, Zwane Mwaikambo wrote:
> On Thu, 24 Jun 2004, Rusty Russell wrote:
>
> > On Wed, 2004-06-23 at 18:02, Zwane Mwaikambo wrote:
> > > 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.
> >
> > Hmmm...
> >
> > You can't move kernel_text_address into module.c, since it isn't
> > compiled for CONFIG_MODULES=n.
>
> Good point, how about if i make modlist_lock a global?

I keep fighting to keep it static 8)

How's this:

Name: Fix race between CONFIG_DEBUG_SLABALLOC and modules
Status: Compiled on 2.6.7
Version: -mm
Signed-off-by: Rusty Russell <[email protected]> (modified)
Signed-off-by: Zwane Mwaikambo <[email protected]>

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.

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32285-linux-2.6.7-mm1/arch/i386/kernel/traps.c .32285-linux-2.6.7-mm1.updated/arch/i386/kernel/traps.c
--- .32285-linux-2.6.7-mm1/arch/i386/kernel/traps.c 2004-06-22 10:37:21.000000000 +1000
+++ .32285-linux-2.6.7-mm1.updated/arch/i386/kernel/traps.c 2004-06-24 17:17:42.000000000 +1000
@@ -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 -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32285-linux-2.6.7-mm1/arch/m68k/kernel/traps.c .32285-linux-2.6.7-mm1.updated/arch/m68k/kernel/traps.c
--- .32285-linux-2.6.7-mm1/arch/m68k/kernel/traps.c 2004-06-22 10:37:22.000000000 +1000
+++ .32285-linux-2.6.7-mm1.updated/arch/m68k/kernel/traps.c 2004-06-24 17:17:29.000000000 +1000
@@ -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 -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32285-linux-2.6.7-mm1/arch/mips/kernel/traps.c .32285-linux-2.6.7-mm1.updated/arch/mips/kernel/traps.c
--- .32285-linux-2.6.7-mm1/arch/mips/kernel/traps.c 2004-05-10 15:12:51.000000000 +1000
+++ .32285-linux-2.6.7-mm1.updated/arch/mips/kernel/traps.c 2004-06-24 17:17:29.000000000 +1000
@@ -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 -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32285-linux-2.6.7-mm1/arch/parisc/kernel/traps.c .32285-linux-2.6.7-mm1.updated/arch/parisc/kernel/traps.c
--- .32285-linux-2.6.7-mm1/arch/parisc/kernel/traps.c 2004-05-10 15:12:54.000000000 +1000
+++ .32285-linux-2.6.7-mm1.updated/arch/parisc/kernel/traps.c 2004-06-24 17:17:29.000000000 +1000
@@ -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 -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32285-linux-2.6.7-mm1/arch/um/kernel/sysrq.c .32285-linux-2.6.7-mm1.updated/arch/um/kernel/sysrq.c
--- .32285-linux-2.6.7-mm1/arch/um/kernel/sysrq.c 2004-05-10 15:13:11.000000000 +1000
+++ .32285-linux-2.6.7-mm1.updated/arch/um/kernel/sysrq.c 2004-06-24 17:17:29.000000000 +1000
@@ -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 -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32285-linux-2.6.7-mm1/arch/x86_64/kernel/traps.c .32285-linux-2.6.7-mm1.updated/arch/x86_64/kernel/traps.c
--- .32285-linux-2.6.7-mm1/arch/x86_64/kernel/traps.c 2004-06-22 10:37:26.000000000 +1000
+++ .32285-linux-2.6.7-mm1.updated/arch/x86_64/kernel/traps.c 2004-06-24 17:17:29.000000000 +1000
@@ -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 -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32285-linux-2.6.7-mm1/include/linux/kernel.h .32285-linux-2.6.7-mm1.updated/include/linux/kernel.h
--- .32285-linux-2.6.7-mm1/include/linux/kernel.h 2004-06-22 10:37:52.000000000 +1000
+++ .32285-linux-2.6.7-mm1.updated/include/linux/kernel.h 2004-06-24 17:17:30.000000000 +1000
@@ -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);

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32285-linux-2.6.7-mm1/include/linux/module.h .32285-linux-2.6.7-mm1.updated/include/linux/module.h
--- .32285-linux-2.6.7-mm1/include/linux/module.h 2004-06-17 08:49:34.000000000 +1000
+++ .32285-linux-2.6.7-mm1.updated/include/linux/module.h 2004-06-24 17:17:30.000000000 +1000
@@ -316,8 +316,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. */
@@ -443,6 +444,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 -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32285-linux-2.6.7-mm1/kernel/extable.c .32285-linux-2.6.7-mm1.updated/kernel/extable.c
--- .32285-linux-2.6.7-mm1/kernel/extable.c 2004-02-04 15:39:15.000000000 +1100
+++ .32285-linux-2.6.7-mm1.updated/kernel/extable.c 2004-06-24 17:17:30.000000000 +1000
@@ -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 -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32285-linux-2.6.7-mm1/kernel/module.c .32285-linux-2.6.7-mm1.updated/kernel/module.c
--- .32285-linux-2.6.7-mm1/kernel/module.c 2004-06-22 10:37:52.000000000 +1000
+++ .32285-linux-2.6.7-mm1.updated/kernel/module.c 2004-06-24 17:17:30.000000000 +1000
@@ -2028,7 +2028,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;

@@ -2039,6 +2039,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)
{


--
Anyone who quotes me in their signature is an idiot -- Rusty Russell

2004-06-24 15:24:50

by Zwane Mwaikambo

[permalink] [raw]
Subject: Re: [PATCH][2.6] Fix module_text_address/store_stackinfo race

On Thu, 24 Jun 2004, Rusty Russell wrote:

> I keep fighting to keep it static 8)
>
> How's this:
>
> Name: Fix race between CONFIG_DEBUG_SLABALLOC and modules
> Status: Compiled on 2.6.7
> Version: -mm
> Signed-off-by: Rusty Russell <[email protected]> (modified)
> Signed-off-by: Zwane Mwaikambo <[email protected]>
>
> 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.

Thanks, looks good, works here.

Zwane