xorl %eax, %eax

Linux kernel IEEE 802.11 SoftMAC Off-by-One Overwrite

leave a comment »

I just saw this in 2.6.30.4’s ChangeLog. The bug was reported by Dan Aloni and it can be found at drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c. Here is the buggy routine from 2.6.30 release of the Linux kernel.

int ieee80211_wx_get_name(struct ieee80211_device *ieee,
                             struct iw_request_info *info,
                             union iwreq_data *wrqu, char *extra)
{
        strcpy(wrqu->name, "802.11");
        if(ieee->modulation & IEEE80211_CCK_MODULATION){
                strcat(wrqu->name, "b");
                if(ieee->modulation & IEEE80211_OFDM_MODULATION)
                        strcat(wrqu->name, "/g");
        }else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
                strcat(wrqu->name, "g");

        if((ieee->state == IEEE80211_LINKED) ||
                (ieee->state == IEEE80211_LINKED_SCANNING))
                strcat(wrqu->name," linked");
        else if(ieee->state != IEEE80211_NOLINK)
                strcat(wrqu->name," link..");


        return 0;
}

It is a simple routine that constructs the name of the wireless device. As we can read at include/linux/wireless.h, structure iwreq_data is defined like this:

/* ------------------------ IOCTL REQUEST ------------------------ */
/*
 * This structure defines the payload of an ioctl, and is used 
 * below.
 *
 * Note that this structure should fit on the memory footprint
 * of iwreq (which is the same as ifreq), which mean a max size of
 * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
 * You should check this when increasing the structures defined
 * above in this file...
 */
union   iwreq_data
{
        /* Config - generic */
        char            name[IFNAMSIZ];
        /* Name : used to verify the presence of  wireless extensions.
         * Name of the protocol/provider... */

        struct iw_point essid;          /* Extended network name */
   ...
};

And constant IFNAMSIZ is simply 16 as we can read from include/linux/if.h. Now, if we move back to ieee80211_wx_get_name() we’ll see that there is a case as Dan Aloni found where the following addition might happen:

“802.11” ++ “b” ++ “/g” ++ ” linked” ++ “\x00”

This result in 17 bytes instead of 16 which is the size of ‘name’ array. The fix to this bug was to change the string routines with the equivalent strl functions like this:

 {
-	strcpy(wrqu->name, "802.11");
+	strlcpy(wrqu->name, "802.11", IFNAMSIZ);
 	if(ieee->modulation & IEEE80211_CCK_MODULATION){
-		strcat(wrqu->name, "b");
+		strlcat(wrqu->name, "b", IFNAMSIZ);
 		if(ieee->modulation & IEEE80211_OFDM_MODULATION)
-			strcat(wrqu->name, "/g");
+			strlcat(wrqu->name, "/g", IFNAMSIZ);
 	}else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
-		strcat(wrqu->name, "g");
+		strlcat(wrqu->name, "g", IFNAMSIZ);
 
 	if((ieee->state == IEEE80211_LINKED) ||
 		(ieee->state == IEEE80211_LINKED_SCANNING))
-		strcat(wrqu->name," linked");
+		strlcat(wrqu->name,"  link", IFNAMSIZ);
 	else if(ieee->state != IEEE80211_NOLINK)
-		strcat(wrqu->name," link..");
+		strlcat(wrqu->name," .....", IFNAMSIZ);
 
 
 	return 0;

Written by xorl

August 7, 2009 at 13:30

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