2004-10-28 04:25:59

by Sorav Bansal

[permalink] [raw]
Subject: BUG REPORT: User/Kernel Pointer bug in sys_poll


Package: linux-kernel-src
Version: 2.4.27

Description: User/Kernel pointer bug/security holl in sys_poll

I think, there is a potential bug/security hole in the sys_poll system
call.

In sys_poll, the user pointer ufds (first arg to sys_poll) goes through
copy_from_user. Then __put_user is called on &ufds->revents.

Since copy_from_user is a read access and __put_user is a write access,
the first call does not verify write-access to ufds. This can be exploited
by a malicious user on a 386 machine (where write-protection in
kernel mode is not enabled .i.e. CONFIG_X86_WP_WORKS_OK is undef).

It seems that this bug can be corrected by replacing the two __put_user
calls in sys_poll by put_user. I am using the latest kernel from
kernel.org .i.e. linux-2.4.27

thanks,
Sorav


2004-10-28 06:03:31

by Sorav Bansal

[permalink] [raw]
Subject: Re: BUG REPORT: User/Kernel Pointer bug in sys_poll


Older x86 architectures (386 and before) allow the kernel to write to any
user location regardless of the write-protect bits.

Hence, with this bug, a user program could write to the write-protected
region of its address space by calling the sys_poll system call and
setting the address and data values appropriately.

An example where this could be exploited is an application running
third-party software. The application may want to write-protect its code
region but with this bug, the third party software will be able to
overwrite write-protected regions by calling sys_poll.

Sorav

On Wed, 27 Oct 2004, Tace wrote:

> sorry but I don't understand, why would it be a
> problem?
>
> --- Sorav Bansal <[email protected]> wrote:
>
> >
> > Package: linux-kernel-src
> > Version: 2.4.27
> >
> > Description: User/Kernel pointer bug/security holl
> > in sys_poll
> >
> > I think, there is a potential bug/security hole in
> > the sys_poll system
> > call.
> >
> > In sys_poll, the user pointer ufds (first arg to
> > sys_poll) goes through
> > copy_from_user. Then __put_user is called on
> > &ufds->revents.
> >
> > Since copy_from_user is a read access and __put_user
> > is a write access,
> > the first call does not verify write-access to ufds.
> > This can be exploited
> > by a malicious user on a 386 machine (where
> > write-protection in
> > kernel mode is not enabled .i.e.
> > CONFIG_X86_WP_WORKS_OK is undef).
> >
> > It seems that this bug can be corrected by replacing
> > the two __put_user
> > calls in sys_poll by put_user. I am using the latest
> > kernel from
> > kernel.org .i.e. linux-2.4.27
> >
> > thanks,
> > Sorav
> >
> > -
> > To unsubscribe from this list: send the line
> > "unsubscribe linux-kernel" in
> > the body of a message to [email protected]
> > More majordomo info at
> > http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at http://www.tux.org/lkml/
> >
>
>
>
>
> __________________________________
> Do you Yahoo!?
> Yahoo! Mail Address AutoComplete - You start. We finish.
> http://promotions.yahoo.com/new_mail
>



2004-10-28 06:39:28

by Andi Kleen

[permalink] [raw]
Subject: Re: BUG REPORT: User/Kernel Pointer bug in sys_poll

Sorav Bansal <[email protected]> writes:

> Older x86 architectures (386 and before) allow the kernel to write to any
> user location regardless of the write-protect bits.

Actually it's only some early steppings of 386 and Linux never ran on
a 286 or earlier. I think the best would be to just ignore it, the affected
user base is very likely zero or very near it. I suspect the
probability of one of these machines still used as a multiuser
machine is very definitely nil.

Cue is that 386 got occassionally broken, and it often took
months to be noticed.

These machines already have other exploitable bugs BTW that have been
ignored for a long time and only been fixed in 2.6.

So just ignore it. It's a non issue, really.

-Andi

2004-10-28 08:51:38

by Denis Vlasenko

[permalink] [raw]
Subject: Re: BUG REPORT: User/Kernel Pointer bug in sys_poll

On Thursday 28 October 2004 09:32, Andi Kleen wrote:
> Sorav Bansal <[email protected]> writes:
>
> > Older x86 architectures (386 and before) allow the kernel to write to any
> > user location regardless of the write-protect bits.
>
> Actually it's only some early steppings of 386 and Linux never ran on
> a 286 or earlier. I think the best would be to just ignore it, the affected
> user base is very likely zero or very near it. I suspect the
> probability of one of these machines still used as a multiuser
> machine is very definitely nil.

People ran Linux on 8086 (DragonLinux,ELKS iirc).

I admire their level of madness, but, really,
it is not useful to spend time on such things.

My personal bottom line of supported hw is 486.
--
vda

2004-10-28 09:53:09

by Andrew Morton

[permalink] [raw]
Subject: Re: BUG REPORT: User/Kernel Pointer bug in sys_poll

Sorav Bansal <[email protected]> wrote:
>
> Older x86 architectures (386 and before) allow the kernel to write to any
> user location regardless of the write-protect bits.
>
> Hence, with this bug, a user program could write to the write-protected
> region of its address space by calling the sys_poll system call and
> setting the address and data values appropriately.

Nope. The only significant difference between copy_from_user() and
__put_user() here is that copy_from_user() checks that the address is not
in the 0xc0000000-0xffffffff range. __put_user() skips that check.

So

if (copy_from_user(kaddr, addr, n))
fail();
__put_user(42, addr);

is safe. We know that the address is in the 0x00000000-0xbfffffff range by
the time we call __put_user(). And if the page at *addr it not writeable
the kernel will take a fault.

So I see no hole. But I wouldn't have coded it that way...

2004-10-28 10:08:25

by Sorav Bansal

[permalink] [raw]
Subject: Re: BUG REPORT: User/Kernel Pointer bug in sys_poll


> Nope. The only significant difference between copy_from_user() and
> __put_user() here is that copy_from_user() checks that the address is not
> in the 0xc0000000-0xffffffff range. __put_user() skips that check.

This is true for modern x86 architectures.

For some older 386's, where Write-Protect does not work okay, there is a
difference between put_user() and copy_from_user(). put_user() performs an
extra check called verify_write() in addition to checking the address
range. Hence, the following code may be unsafe when running on those
machines.

> So
>
> if (copy_from_user(kaddr, addr, n))
> fail();
> __put_user(42, addr);
>
> is safe. We know that the address is in the 0x00000000-0xbfffffff range by
> the time we call __put_user(). And if the page at *addr it not writeable
> the kernel will take a fault.

In older 386's, the kernel will NOT take a fault and write to the
write-protected region.

But then, maybe 386 is too old to worry about :-)

2004-10-28 20:52:43

by Alan

[permalink] [raw]
Subject: Re: BUG REPORT: User/Kernel Pointer bug in sys_poll

On Iau, 2004-10-28 at 10:48, Andrew Morton wrote:
> is safe. We know that the address is in the 0x00000000-0xbfffffff range by
> the time we call __put_user(). And if the page at *addr it not writeable
> the kernel will take a fault.
>
> So I see no hole. But I wouldn't have coded it that way...

On x86 maybe. I think he's right in the sense that we may have a non x86
platform that this is not safe on.