xorl %eax, %eax

CVE-2008-2136: SIT Memory Leaks

leave a comment »

On 9 May 2008 the issue made public on a mailing list. The vulnerability was found by Paul Marks. As it is obvious from the patch (diff file) attached to the email. The bug is located at the SIT interfaces of the IPv6 protocol implementation. According to Paul Marks this hasn’t changed since kernel version 2.4.4 (which was on 2001). SIT (Simple Internet Transition) is a similar to IPIP protocol used to create virtual tunneling interfaces which can be used to interconnect isolated IPv6 networks with IPv4 ones. This feature is provided to the Linux kernel through the ‘ipv6‘ module. This tunnels are most commonly refered as IPv6 to IPv4 tunnel devices.

Since this issue affects from 2.4.4 to 2.6.25.3 we will use the 2.6.25.2’s source code. The ipip6_rcv() function can be found at net/ipv6/sit.c, line 410. Here is a cut down version of it. It includes just the interesting for the attacker parts:

 410  static int ipip6_rcv(struct sk_buff *skb)
 411  {
 412          struct iphdr *iph;
 413          struct ip_tunnel *tunnel;
 414
 415          if(!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 416                             goto out;
 417
 418          iph = ip_hdr(skb);
 419
 420          read_lock(&ipip6_lock);
 421          if ((tunnel = ipip6_tunnel_lookup(iph->saddr, iph->daddr))
                                 ...
        Then change the skb according to the tunnel
                                 ...
 429          if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
 430              !isatap_srcok(skb, iph, tunnel->dev))
                                 ...
        Then if the interface is ISATAP (RFC-4214) and
        the source isn't ISATAP, free() the space allocated
        and return 0;
                                 ...
 436          tunnel->stat.rx_packets++;
 437          tunnel->stat.rx_bytes += skb->len;
                                 ...
                    And stuff like that
                                 ...
 445          return 0;
 446       }
 447
 448       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 449       kfree_skb(skb);
 450       read_unlock(&ipip6_lock);
 451 out:
 452       return 0;
 452 }
 454

The problem Paul Marks spotted can be found at line 415. As you can see if the result of pskb_may_pull() isn’t 0 it works as expected. And at line 449 it uses kfree_skb() to free the allocated space. However, if the pskb_may_pull() return a value equal to zero, the condition will be true and it will ‘goto out‘. Label ‘out‘ can be found at line 451. The only thing that it includes is: return 0; This means that the allocated kernel space for skb won’t be freed. This memory leak can exchaust all the available memory and lead to a denial of service condition. But when does the pskb_may_pull() returns a value equal to zero?
This function is located at include/linux/skbuff.h, line 984. Here it is:

 984 static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len)
 985 {
 986         if (likely(len <= skb_headlen(skb)))
 987                 return 1;
 988         if (unlikely(len < skb->len))
 989                 return 0;
 990         return __pskb_pull_tail(skb, len-skb_headlen(skb)) != NULL;
 991 }
 992

So, we have to make our packet hit the first condition of ipip6_rcv(), the skb_headlen() obviously is just this:

 826 static inline unsigned int skb_headlen(const struct sk_buff *skb)
 827 {
 828         return skb->len - skb->data_len;
 829 }

This means that in order to trigger the ‘goto out‘ we have to make a packet that its length (skb->len) is less than the sizeof(struct ipv6hdr). This way the executed code will be:

        if (!0)
          goto out;

Thus, if the attacker keeps sending malformed packets to the SIT tunnel the skb buffer won’t be freed and finally this could lead to denial of service through kernel memory consumption.

Written by xorl

January 3, 2009 at 21:04

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