xorl %eax, %eax

Linux kernel Tree Connect CIFS Remote Buffer Overflow

with 3 comments

This is a pretty awesome bug found by fefe and affects almost every 2.6 kernel. This massive destruction bug can be found under fs/cifs/connect.c. Here is the code from 2.6.28.9 release of the Linux kernel:

3441 int
3442 CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3443          const char *tree, struct cifsTconInfo *tcon,
3444          const struct nls_table *nls_codepage)
3445 {
3446        struct smb_hdr *smb_buffer;
3447        struct smb_hdr *smb_buffer_response;
3448        TCONX_REQ *pSMB;
3449        TCONX_RSP *pSMBr;
3450        unsigned char *bcc_ptr;
3451        int rc = 0;
3452        int length;
3453        __u16 count;
        ...
3458        smb_buffer = cifs_buf_get();
        ...
3561                if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3562                        length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3563                        if ((bcc_ptr + (2 * length)) -
3564                             pByteArea(smb_buffer_response) <=
3565                            BCC(smb_buffer_response)) {
3566                                kfree(tcon->nativeFileSystem);
3567                                tcon->nativeFileSystem =
3568                                    kzalloc(length + 2, GFP_KERNEL);
        ...
3579                        /* else do not bother copying these information fields*/
        ...
3606        cifs_buf_release(smb_buffer);
3607        return rc;
3608 }


As you can see, if the user controlled buffer smb_buffer (line 3458) is Unicode (line 3561), it calculates its length (again, this is a signed integer for some reason but that’s irrelevant here) using UniStrnlen() and if this is less than, or equal to smb_buffer_response‘s bytes using BCC() macro which is defined as fs/cifs/cifspdu.h simply like this:

416 /* given a pointer to an smb_hdr retrieve the value of byte count */
417 #define BCC(smb_var) (*(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount)))
418 #define BCC_LE(smb_var) (*(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount)))

Then, free the allocated native filesystem memory (line 3566), and re-allocate it using kzalloc() at line 3568. This should have enough size to store the unicode string but instead of doing:

(length + 1) * 2

Since unicode needs at least 2 bytes for each character and another one for NULL termination, it does this:

length + 2

Clearly, this insufficient allocation leads to a nice remotely exploitable buffer overflow. The patch was simple as that:

                                tcon->nativeFileSystem =
-                                   kzalloc(length + 2, GFP_KERNEL);
+                                   kzalloc(2*(length + 1), GFP_KERNEL);
                                if (tcon->nativeFileSystem)

This definitely worth more research since it might still be exploitable. Did you read Suresh Jayaraman’s of SUSE email? Have fun! :-)

Written by xorl

April 7, 2009 at 15:55

Posted in linux, vulnerabilities

3 Responses

Subscribe to comments with RSS.

  1. UniStrnLen returns a character count, not byte count. Illegal UTF-8 encodings can have up to six octets, legal ones can have up to four. There’s a convientient constant defined exactly for this purpose: NLS_MAX_CHARSET_SIZE, defined as 6.

    You do know we’re talking about string conversion using codepages, right? Right, that’s why you keep refering to Unicode as if it’s the only possible encoding we might be dealing with (I know there’s an if testing for Uni, I’m tlking about what you do after that…)

    Strat

    April 13, 2009 at 14:51

  2. thanks this post. I made some adjustments

    Степан

    June 11, 2009 at 11:08

  3. I’m surely missing something, but I think that this is not remotely exploitable unless you can remotely trigger a mount. Seems more like a client-side bug to me.

    Alfred

    December 3, 2009 at 00:09


Leave a comment