xorl %eax, %eax

CVE-2010-2522: USAGI Mobile IPv6 for Linux NETLINK Message Spoofing

with 3 comments

This vulnerability was discovered and reported by Sebastian Krahmer (aka stealth). Here is the buggy code:

static int xfrm_rcv(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        switch (n->nlmsg_type) {
        case XFRM_MSG_ACQUIRE:
                /* Start RO or send BRR */
                if (is_mn())
                        parse_acquire(n);
                break;
        case XFRM_MSG_REPORT:
                parse_report(n);
                break;
        }
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        return 0;
}

This first code snippet was taken from src/xfrm.c which is the XFRM receiving routine of the Mobile IPv6 Daemon for Linux developed by USAGI Project. As you can read, it initially sets this thread’s state to disable cancellation. Then it checks the received NetLink header’s message type. If it is ‘XFRM_MSG_ACQUIRE’ it will check if configuration entity is equal to ‘MIP6_ENTITY_MN’ as we can read at src/conf.h:

static inline int is_mn(void)
{
        return conf.mip6_entity == MIP6_ENTITY_MN;
}

And finally, invoke parse_acquire() to parse that NetLink message. Next, if its type is set to ‘XFRM_MSG_REPORT’ it will immediately pass it for parsing to parse_report(). Both parse_acquire() and parse_report() do not include any checks of the source of the NetLink message. Because of this a user could send such messages which are normally only received by the kernel.
Sebastian Krahmer suggests the following patch to fix this vulnerability:

@@ -1939,6 +1939,11 @@
 static int xfrm_rcv(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+	/* only accept messages from kernel */
+	if (who->nl_pid)
+		goto out;
+
 	switch (n->nlmsg_type) {
 	case XFRM_MSG_ACQUIRE:
 		/* Start RO or send BRR */
@@ -1949,6 +1954,9 @@
 		parse_report(n);
 		break;
 	}
+
+
+out:
 	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
 	return 0;
 }

That checks ‘who->nl_pid’ for non-zero values. If it encounters a different one it will jump to the ‘out’ label that resets thread’s cancel state and returns.
The second routine susceptible to this vulnerability can be found at src/movement.c like this:

static int process_nlmsg(struct sockaddr_nl *who,
                         struct nlmsghdr *n, void *arg)
{
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        switch (n->nlmsg_type) {
        case RTM_NEWLINK:
        case RTM_DELLINK:
                /* interface or link, up or down */ 
                process_link(n, arg);
                break;
        case RTM_NEWNEIGH:
                /* changes in reachability state of default router */
                process_neigh(n, arg);
                break;
        case RTM_NEWADDR:
        case RTM_DELADDR:
                /* new or deleted CoAs */
                process_addr(n, arg);
                break;
        default:
                /* To do: listen to changes in default and prefix routes(?) */
                break;
        }
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        return 0;
}

This function processes the received NetLink message. The concept is pretty much the same. It just checks the NetLink message’s type and chooses the appropriate processing routine according to that type. As you can see there is no check on the source’s ID in this code either. S. Krahmer’s fix suggestion is the following:

@@ -818,6 +818,11 @@
 			 struct nlmsghdr *n, void *arg)
 {
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+	/* only accept messages from kernel */
+	if (who->nl_pid)
+		goto out;
+
 	switch (n->nlmsg_type) {
 	case RTM_NEWLINK:
 	case RTM_DELLINK:
@@ -837,6 +842,8 @@
 		/* To do: listen to changes in default and prefix routes(?) */
 		break;
 	}
+
+out:
 	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
 	return 0;
 }

Which is similar to the one applied to xfrm_rcv(). From a quick look I had in the latest release of mipv6 there is still no patch committed to patch these vulnerabilities.

Written by xorl

October 19, 2010 at 14:30

Posted in bugs

3 Responses

Subscribe to comments with RSS.

  1. you missed the most important part :)
    if you look closer the patch fixes a remote buffer overflow
    while handling icmp6 messages. the netlink fix is just to
    make it complete but its not a dangerous issue.

    icke

    October 20, 2010 at 08:15

  2. I didn’t miss, it was assigned a different CVE ID to it (CVE-2010-2523). I’ll write about it too. :)

    xorl

    October 20, 2010 at 08:45

  3. not necessary to write about it. rather have a look at $ORIGIN :D

    icke

    October 20, 2010 at 15:36


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