xorl %eax, %eax

CVE-2011-3191: Linux kernel CIFSFindNext Signedness Issue

leave a comment »

This issue was reported by Darren Lavender and you can find the susceptible code under fs/cifs/cifssmb.c where SMB/CIFS PDU handling routines are located.

int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
                 __u16 searchHandle, struct cifs_search_info *psrch_inf)
{
        TRANSACTION2_FNEXT_REQ *pSMB = NULL;
        TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
        T2_FNEXT_RSP_PARMS *parms;
        char *response_data;
        int rc = 0;
        int bytes_returned, name_len;
        __u16 params, byte_count;
     ...
        name_len = psrch_inf->resume_name_len;
        params += name_len;
        if (name_len < PATH_MAX) {
                memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
                byte_count += name_len;
                /* 14 byte parm len above enough for 2 byte null terminator */
                pSMB->ResumeFileName[name_len] = 0;
                pSMB->ResumeFileName[name_len+1] = 0;
        } else {
                rc = -EINVAL;
                goto FNext2_err_exit;
        }
     ...
FNext2_err_exit:
        if (rc != 0)
                cifs_buf_release(pSMB);
        return rc;
}

From the given code snippet you can see that ‘name_len’ is declared as signed integer and it is initialized with the value of ‘psrch_inf->resume_name_len’ which is unsigned integer as we can see in fs/cifs/cifsglob.h header file where it is defined.

/*
 * One of these for each open instance of a file
 */
struct cifs_search_info {
     ...
        unsigned int resume_name_len;
     ...
};

Also, as Jeff Layton pointed out in some cases this value is derived directly from the server making this vulnerability a remote security hole. Back to the code snippet of CIFSFindNext() and assuming that the value of ‘name_len’ is large enough to make it look like a negative number, it could bypass the ‘if’ check with ‘PATH_MAX’ which is defined in include/linux/limits.h header file.

#define PATH_MAX        4096    /* # chars in a path name including nul */

And thus, lead to the memcpy() call using a huge value, the unsigned value of ‘name_len’, for the number of Bytes to copy. So, this vulnerability potentially leads to remote memory corruption.
Of course, the fix was to change the data type of the aforementioned variable as you can see in the below diff file.

 	int rc = 0;
-	int bytes_returned, name_len;
+	int bytes_returned;
+	unsigned int name_len;
 	__u16 params, byte_count;

Written by xorl

September 10, 2011 at 01:37

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