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:

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

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

    ReplyDelete
  3. I'm safe, I run Windows

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

    ReplyDelete
  5. good thing i run plan9

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

    ReplyDelete
  7. 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/

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

    ReplyDelete
  9. 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.

    ReplyDelete
  10. > 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).

    ReplyDelete
  11. 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

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

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

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

    Codifex

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

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

    ReplyDelete
  17. 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 ?

    ReplyDelete
  18. 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!

    ReplyDelete
  19. 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".

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

    ReplyDelete
  21. 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).

    ReplyDelete
  22. 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.

    ReplyDelete
  23. This definetly does not work on fedora with selinux enforcing.

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

    ReplyDelete
  25. 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.

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

    ReplyDelete
  27. 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.

    ReplyDelete
  28. @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.

    ReplyDelete