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! :-)