xorl %eax, %eax

CVE-2009-3612: Linux kernel tc_fill_node() 2 Bytes Information Leak

leave a comment »

This vulnerability was introduced by the incomplete fix for CVE-2005-4881. On October, Jiri Pirko of Red Hat reported the bug and after some time, the bugfix was applied in 2.6.32-rc5 as we can read from its ChangeLog file.
Anyway, here is the susceptible code from 2.6.31 release of the Linux kernel…

static int tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp,
                         unsigned long fh, u32 pid, u32 seq, u16 flags, int event)
{
        struct tcmsg *tcm;
        struct nlmsghdr  *nlh;
        unsigned char *b = skb_tail_pointer(skb);

        nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
        tcm = NLMSG_DATA(nlh);
        tcm->tcm_family = AF_UNSPEC;
        tcm->tcm__pad1 = 0;
        tcm->tcm__pad1 = 0;
        tcm->tcm_ifindex = qdisc_dev(tp->q)->ifindex;
        tcm->tcm_parent = tp->classid;
        tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol);
        NLA_PUT_STRING(skb, TCA_KIND, tp->ops->kind);
        tcm->tcm_handle = fh;
        if (RTM_DELTFILTER != event) {
                tcm->tcm_handle = 0;
                if (tp->ops->dump && tp->ops->dump(tp, fh, skb, tcm) < 0)
                        goto nla_put_failure;
        }
        nlh->nlmsg_len = skb_tail_pointer(skb) - b;
        return skb->len;

nlmsg_failure:
nla_put_failure:
        nlmsg_trim(skb, b);
        return -1;
}

It is quite obvious that this routine from net/sched/cls_api.c is used to initialize a ‘tcmsg’ structure (which stands for Traffic Control Messages) structure. This function is utilized by routing NetLink sockets, also known as rtnetlink. All of the available message types for rtnetlink sockets are available at include/linux/rtnetlink.h, and the ‘tcmsg’ structure is defined like this:

struct tcmsg
{
        unsigned char   tcm_family;
        unsigned char   tcm__pad1;
        unsigned short  tcm__pad2;
        int             tcm_ifindex;
        __u32           tcm_handle;
        __u32           tcm_parent;
        __u32           tcm_info;
};

As you can easily notice, the code from tcf_fill_node() initializes twice the ‘tcm__pad1’ unsigned character (meaning size of 1 Byte) to 0 and it does not initialize ‘tcm__pad2’ which is an unsigned short integer (which has size of 2 Bytes) at all.
This was fixed by adding the missing assignment like this:

        tcm->tcm__pad1 = 0;
-       tcm->tcm__pad1 = 0;
+       tcm->tcm__pad2 = 0;
        tcm->tcm_ifindex = qdisc_dev(tp->q)->ifindex;

The trigger is quite simple, using a NETLINK_ROUTE socket and a message type of RTM_GETTCLASS as the researchers at vigilance.fr noticed, you can obtain 2 Bytes of kernel memory.

Written by xorl

October 22, 2009 at 21:28

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