Thursday, August 13, 2009

Linux NULL pointer dereference due to incorrect proto_ops initializations (CVE-2009-2692)

EDIT2: Here is RedHat's official mitigation recommendation
EDIT3: Brad Spengler also wrote an exploit for this and published it. The bug triggering is based on our exploit which leaked to Brad though the private vendor-sec mailing list. He implements the personality trick Tavis and I published in June to bypass mmap_min_addr and also makes use of a feature that allows any unconfined user to gain the right to map at address zero in Redhat's default SELinux policy. He wrote a reliable shellcode for this one that should work pretty much anywhere on x86 and x86_64 machines.
EDIT4: if you use Debian or Ubuntu on your machine, I have specifically updated the kernelsec Debian/Ubuntu GrSecurity packages to protect against this bug and others.
EDIT5: Zinx wrote an ARM Android root exploit
EDIT6: Ramon de Carvalho Valle wrote a PPC/PPC64/x86_64/i386 exploit

Tavis Ormandy and myself have recently found and investigated a Linux kernel vulnerability (CVE-2009-2692). It affects all 2.4 and 2.6 kernels since 2001 on all architectures. We believe this is the public vulnerability affecting the greatest number of kernel versions.

The issue lies in how Linux deals with unavailable operations for some protocols. sock_sendpage and others don't check for NULL pointers before dereferencing operations in the ops structure. Instead the kernel relies on correct initialization of those proto_ops structures with stubs (such as sock_no_sendpage) instead of NULL pointers.

At first sight, the code in af_ipx.c looks correct and seems to initialize .sendpage properly. However, due to a bug in the SOCKOPS_WRAP macro, sock_sendpage will not be initialized. This code is very fragile and there are many other protocols where proto_ops are not correctly initialized at all (vulnerable even without the bug in SOCKOPS_WRAP), see bluetooth for instance.

So it was decided that instead of patching all those protocols and continue to rely on this very fragile code, sock_sendpage would get patched to check against NULL. This was already the way sock_splice_read and others were handled.

Since it leads to the kernel executing code at NULL, the vulnerability is as trivial as it can get to exploit (edit: that's for local privilege escalation and on Intel architectures): an attacker can just put code in the first page that will get executed with kernel privileges. Our exploit took a few minutes to adapt from a previous one:

$ ./leeches
// ------------------------------------------------------
// sendpage linux local ring0
// ---------------- taviso@sdf.lonestar.org, julien@cr0.org
// leeches.c:Aug 11 2009
// GreetZ: LiquidK, lcamtuf, Spoonm, novocainated, asiraP, ScaryBeasts, spender, pipacs, stealth, jagger, redpig, Neel and all the other leeches we forgot to mention!
Enjoy some photography while at ring0 @ http://flickr.com/meder
For our webapp friends, here is an XSS executing at ring 0: javascript:alert(1);
shellcode now executing chmod("/bin/sh", 04755), welcome to ring0
Killed
$ sh
# id
uid=1000(julien) gid=1000(julien) euid=0(root)

On x86/x86_64, this issue could be mitigated by three things:
  • the recent mmap_min_addr feature. Note that this feature has known issues until at least 2.6.30.2. See also this LWN article.
  • on IA32 with PaX/GrSecurity, the KERNEXEC feature (x86 only)
  • not implementing affected protocols (a.k.a., reducing your attack surface by disabling what you don't need): PF_APPLETALK, PF_IPX, PF_IRDA, PF_X25, PF_AX25, PF_BLUETOOTH, PF_IUCV, IPPROTO_SCTP/PF_INET6, PF_PPPOX, PF_ISDN, but there may be more. (Update: See RedHat's mitigation)
This patch should be applied to fix this issue.

You can read our advisory here.

Note: this has been featured on Slashdot, OSNews, TheRegister, ZDNet and others

32 comments:

Anonymous said...

It's not exploitable for code execution on all architectures. My sparc server for instance is safe ;)

Anonymous said...

It's already been patched, just make sure you've run the update.

Anonymous said...

I'm safe, I run Windows

Anonymous said...

One more reason I'm glad to have PaX and GrSecurity.

Anonymous said...

good thing i run plan9

Anonymous said...

How about some exploit code??
First person to release c0de gets a beer on me!

Anonymous said...

What if you have IPX completely disabled in your kernel? Looking at your discovery, I can see how this would be a problem for people with very modular kernels/

Anonymous said...

http://www.securityfocus.com/bid/36038/exploit
beer please now

Anonymous said...

This is one reason so many 64b systems (Tru64 on Alpha being a good example) prevent mapping the first 32 bits of address space. Surprising that Linux doesn't do the same.

Anonymous said...

> This is one reason so many 64b systems
> (Tru64 on Alpha being a good example
> prevent mapping the first 32 bits of
> address space. Surprising that Linux
> doesn't do the same.

?? First of all - the whole problem has nothing to do with architecture of the used CPU (intel, non-intel, 32bit, 64bit).

Secondly - Linux also offers such protection, but it was somehow flawed until one of the kernel versions

3rdly - It is guaranteed on some systems (SVR4) that the fisrt page is always mapped (PROT_READ afair), so linux tries to emulate that behavior via the personality mechanism - http://linux.die.net/man/2/personality - and that is where the bug lied (the one with mapping zero page).

nojoy said...

Good find, great work.

Anonymous said...

Exploit code has been available at http://grsecurity.net/~spender/wunderbar_emporium.tgz

Works on all affected kernels: both x86 and x64, 4k stacks or 8k stacks, cred framework or not. Disables SELinux, AppArmor, LSM, and auditing. Also plays an embedded movie if the host is up to it.

-Brad

Anonymous said...

Can anybody explain why http://www.securityfocus.com/bid/36038/exploit only works once?

Fanf said...

Congrats for the discover !

Anonymous said...

Yet another reason to use some alternative with better track record wrt security, like Solaris or *BSD.

Anonymous said...

Looks like it's finally kernel upgrade time!
Goodbye Linux_2.6.19, I'll miss you.

Codifex

Anonymous said...

Don't use the one from securityfocus, they have an old version of the exploit.

Anonymous said...

UNABLE TO MAP ZERO PAGE! on up to date Fedora with SELinux. Problem addressed by Red Hat when fixing CVE-2009-1895 recently?

Anonymous said...

Why can't the kernel track the process that map page zero and does extra stuff when switching from user mode to kernel mode (update mmu to make it not excecutable, ...)

Of course this will slowdown these processes but are there performance program that depend of that ?
Wine ?

Christoph said...

Looks like you where to fast when you thanked Dan, because SELinux does indeed stop this:

$ LANG=C sh wunderbar_emporium.sh
runcon: invalid context:
unconfined_u:unconfined_r:initrc_t:s0-s0:c0.c1023: Invalid argument
UNABLE TO MAP ZERO PAGE!

Christoph said...

Doesn't work with SELinux, although you claim the opposite in the source:

sh wunderbar_emporium.sh
runcon: invalid context:
unconfined_u:unconfined_r:initrc_t:s0-s0:c0.c1023: Invalid argument
UNABLE TO MAP ZERO PAGE!

and the raw audit message for this:
localhost.localdomain type=AVC msg=audit(1250278420.753:27501): avc: denied { mmap_zero } for pid=16933 comm="exploit" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=memprotect

So obviously you were to fast when you thanked Dan for "great SELinux bypass".

Lam said...

Fedora's SELinux policy (asuuming you leave it enforcing) protects from the exploit (runcon can't change the type).

Emsi said...

So there's actually two bugs. One is NULL pointer dereference and the other is allowing to mmap (presumably unmmapable) memory at 0x0 location (even if /proc/sys/vm/mmap_min_addr > 0).

Julien Tinnes said...

Here's a reply to some of the comments (not all, sorry):

- @Anonymous: you're correct, about SPARC. Interestingly, IA32 could also be safe but is not for performances reasons (unless you use Linux 2.0 or PaX KERNEXEC/UDEREF). x86_64 however killed segmentation :(
- About mapping to Null. This should be protected by mmap_min_addr since Linux 2.6.23. Last month, Tavis and I published a way to bypass it by using personalities and Pulseaudio. Brad Spengler then implemented this technique in an exploit and noticed that it worked even without the Pulseaudio trick. The reason was the default SELinux policy allowing unconfined users to mmap at address zero.

Anonymous said...

This definetly does not work on fedora with selinux enforcing.

Anonymous said...

my fedora 11 with SELinux enforcing is also safe, the exploit doesnt work or did i miss something?

Anonymous said...

It did exploit Fedora SELinux up until August 13, then was patched. I successfully exploited Kernel 2.6.29.6-213.fc11.i586 with this mechanism.

Anonymous said...

http://www.doecirc.energy.gov/bulletins/t-217.shtml
Julien can u give more info about this vuln and how to trigger it.
thanks

yenimoda said...

oo thanx bro. good bilgi..

John Cooper said...

Is it not normal procedure to inform the Kernel maintainers before publishing an exploit to the world? It took until 13th August for a patch to be released.

Julien Tinnes said...

@John: I have no idea what you're talking about. We also worked on the patch, which was released even before the advisory.

I even link to it from the blog post.

saksit said...

I have no idea

Post a Comment