2007-11-11 23:41:07

by Jesper Juhl

[permalink] [raw]
Subject: mm_release() call in exit_mm() looks dangerous

In kernel/exit.c we have this code :

static void exit_mm(struct task_struct * tsk)
{
struct mm_struct *mm = tsk->mm;

mm_release(tsk, mm);
if (!mm)
return;
...


But, mm_release() may dereference it's second argument ('mm'), so
shouldn't we be doing the "!mm" test *before* we call mm_release() and
not after?
I don't know the mm code well enough to be able to tell if some of the
other stuff mm_release does needs to be done always and the mm
dereference can't actually happen, but maybe someone else who knows
the code better can tell... In any case, what's currently there looks
a little shaky..

--
Jesper Juhl <[email protected]>
Don't top-post http://www.catb.org/~esr/jargon/html/T/top-post.html
Plain text mails only, please http://www.expita.com/nomime.html


2007-11-13 00:49:54

by Jeremy Fitzhardinge

[permalink] [raw]
Subject: Re: mm_release() call in exit_mm() looks dangerous

Jesper Juhl wrote:
> In kernel/exit.c we have this code :
>
> static void exit_mm(struct task_struct * tsk)
> {
> struct mm_struct *mm = tsk->mm;
>
> mm_release(tsk, mm);
> if (!mm)
> return;
> ...
>
>
> But, mm_release() may dereference it's second argument ('mm'), so
> shouldn't we be doing the "!mm" test *before* we call mm_release() and
> not after?
> I don't know the mm code well enough to be able to tell if some of the
> other stuff mm_release does needs to be done always and the mm
> dereference can't actually happen, but maybe someone else who knows
> the code better can tell... In any case, what's currently there looks
> a little shaky..
>

Yeah, it looks wrong. mm_release() calls deactivate_mm() as its first
act, which could well dereference mm (though it often doesn't).

J

2007-11-16 00:35:10

by Jesper Juhl

[permalink] [raw]
Subject: Re: mm_release() call in exit_mm() looks dangerous

On 13/11/2007, Jeremy Fitzhardinge <[email protected]> wrote:
> Jesper Juhl wrote:
> > In kernel/exit.c we have this code :
> >
> > static void exit_mm(struct task_struct * tsk)
> > {
> > struct mm_struct *mm = tsk->mm;
> >
> > mm_release(tsk, mm);
> > if (!mm)
> > return;
> > ...
> >
> >
> > But, mm_release() may dereference it's second argument ('mm'), so
> > shouldn't we be doing the "!mm" test *before* we call mm_release() and
> > not after?
> > I don't know the mm code well enough to be able to tell if some of the
> > other stuff mm_release does needs to be done always and the mm
> > dereference can't actually happen, but maybe someone else who knows
> > the code better can tell... In any case, what's currently there looks
> > a little shaky..
> >
>
> Yeah, it looks wrong. mm_release() calls deactivate_mm() as its first
> act, which could well dereference mm (though it often doesn't).
>
So, whould simply moving the !mm check up as the first in the function
be an appropriate way to deal with this?

--
Jesper Juhl <[email protected]>
Don't top-post http://www.catb.org/~esr/jargon/html/T/top-post.html
Plain text mails only, please http://www.expita.com/nomime.html

2007-11-16 02:28:21

by Cong Wang

[permalink] [raw]
Subject: [Patch] kernel/exit.c: Fix use-before-check in exit_mm()

On Fri, Nov 16, 2007 at 01:34:54AM +0100, Jesper Juhl wrote:
>On 13/11/2007, Jeremy Fitzhardinge <[email protected]> wrote:
>> Jesper Juhl wrote:
>> > In kernel/exit.c we have this code :
>> >
>> > static void exit_mm(struct task_struct * tsk)
>> > {
>> > struct mm_struct *mm = tsk->mm;
>> >
>> > mm_release(tsk, mm);
>> > if (!mm)
>> > return;
>> > ...
>> >
>> >
>> > But, mm_release() may dereference it's second argument ('mm'), so
>> > shouldn't we be doing the "!mm" test *before* we call mm_release() and
>> > not after?
>> > I don't know the mm code well enough to be able to tell if some of the
>> > other stuff mm_release does needs to be done always and the mm
>> > dereference can't actually happen, but maybe someone else who knows
>> > the code better can tell... In any case, what's currently there looks
>> > a little shaky..
>> >
>>
>> Yeah, it looks wrong. mm_release() calls deactivate_mm() as its first
>> act, which could well dereference mm (though it often doesn't).
>>
>So, whould simply moving the !mm check up as the first in the function
>be an appropriate way to deal with this?

I think yes. Patch below.

Fix use-before-check in kernel/exit.c

Signed-off-by: WANG Cong <[email protected]>

---

diff --git a/kernel/exit.c b/kernel/exit.c
index cd0f1d4..dca1e0d 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -558,9 +558,9 @@ static void exit_mm(struct task_struct * tsk)
{
struct mm_struct *mm = tsk->mm;

- mm_release(tsk, mm);
if (!mm)
return;
+ mm_release(tsk, mm);
/*
* Serialize with any possible pending coredump.
* We must hold mmap_sem around checking core_waiters