xorl %eax, %eax

CVE-2009-1265: Linux kernel ROSE/X.25/NetROM Integer Overflows

leave a comment »

So.. this was reported by Thomas Pollet on 8 April 2008 and fixed by Alan Cox on 27 March 2009. It affects Linux kernel prior to 2.6.30-rc1 (including 2.4 branch). Here, I’ll be using 2.6.24.4 to demonstrate this. The first of the three bugs under this CVE ID is on NetROM, the vulnerable code can be found at: net/netrom/af_netrom.c:

1020 static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
1021                       struct msghdr *msg, size_t len)
1022 {
1023        struct sock *sk = sock->sk;
         ...
1030        int size;
         ...
1075        SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n");
1076
1077        /* Build a packet */
1078        SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n");
1079        size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
1080
1081        if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
1082                goto out;
         ...
1103        /*
1104         *      Put the data on the end
1105         */
1106        skb_put(skb, len);
         ...
1110        /* User data follows immediately after the NET/ROM transport header */
1111        if (memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len)) {
         ...
1125        nr_output(sk, skb);     /* Shove it onto the queue */
         ...
1130        return err;
1131 }

Impressive, isn’t it? You can directly use sendmsg() on a NetROM socket (AF_NETROM) with a length of.. let’s say 0xffffffff0 and at line 1079 you’re going to have this:

(int) size = 0xffffffff0 + 15 + 5;

This will make size contain value 4 since it will overflow and wrap around. Next, this size variable is being used at line 1081. Function sock_alloc_send_skb() being invoked there, this is part of net/core/sock.c and it is the send/receive generic buffer handler for sockets. Its second argument is used to calculate the header length. At last, at line 1106 skb_put() of include/linux/skbuff.h is being called to add len data into skb buffer!!! Finally, at line 1125 a call at nr_output() of net/netrom/nr_out.c is made to pass the data to the queue to send it back to the caller. The above bug can lead to a huge information leak from kernel memory and potential crash (or something more?) because of read out of bounds. This was patched like this:

        SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n");

-       /* Build a packet */
+       /* Build a packet - the conventional user limit is 236 bytes. We can
+          do ludicrously large NetROM frames but must not overflow */
+       if (len > 65536)
+               return -EMSGSIZE;
+
        SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n");

Now, the next one… This is on ROSE implementation. You can find the bug at net/rose/af_rose.c:

1043 static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
1044                         struct msghdr *msg, size_t len)
1045 {
1046        struct sock *sk = sock->sk;
         ...
1051        struct sk_buff *skb;
         ...
1053        int n, size, qbit = 0;
         ...
1101        /* Build a packet */
1102        SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n");
1103        size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;
1104
1105        if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
1106                return err;
         ...
1116        skb_put(skb, len);
1117
1118        err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
         ...
1205        skb_queue_tail(&sk->sk_write_queue, skb);       /* Shove it onto the queue */
         ...
1210        return len;
1211 }


It’s pretty much the same. Signed integer size (line 1053) can overflow at line 1103 since we have a calculation like this:

(int) size = (size_t) len + 16 + 73 + 3;

And this is used on sock_alloc_send_skb() and consequently on skb_put() to be transmitted back to the user requested it. Another kernel memory information leak. This was patched like this:

        /* Build a packet */
        SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n");
+       /* Sanity check the packet size */
+       if (len > 65535)
+               return -EMSGSIZE;
+
        size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;/

To trigger it just create an AF_ROSE socket with length enough to wrap around and overflow the calculation of line 1103. :)
The last on was at X.25 implementation. You can find this under net/x25/af_x25.c and its almost exactly the same… Here it is:

986 static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
987                       struct msghdr *msg, size_t len)
988 {
989        struct sock *sk = sock->sk;
       ...
993        struct sk_buff *skb;
       ...
996        size_t size;
       ...
1047        /* Build a packet */
1048        SOCK_DEBUG(sk, "x25_sendmsg: sendto: building packet.\n");
1049
1050        if ((msg->msg_flags & MSG_OOB) && len > 32)
1051                len = 32;
1052
1053        size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
1054
1055        skb = sock_alloc_send_skb(sk, size, noblock, &rc);
      ...
1068        skb_put(skb, len);
      ...
1127        if (msg->msg_flags & MSG_OOB)
1128                skb_queue_tail(&x25->interrupt_out_queue, skb);
      ...
1160 }

Wow!!! Impressive! A Linux kernel developer uses size_t for length storage (line 996), that surprised me a little. Anyway, this is not a signedness issue. The bug is that user controlled len (line 987) is checked whether it supports out-of-band data (line 1050) and unless it does the size is calculated like this:

(size_t) size = (size_t) len + 18 + 4;

You can overflow this and the proceeding call to skb_put() will give you your precious kernel memory data remotely! And all these by just creating an AF_X25 socket with an evil length! :P
Again, the patch was simply:

        }

+       /* Sanity check the packet size */
+       if (len > 65535) {
+               rc = -EMSGSIZE;
+               goto out;
+       }
+
        SOCK_DEBUG(sk, "x25_sendmsg: sendto: Addresses built.\n");

Written by xorl

April 10, 2009 at 14:55

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