cifs: fix unicode string area word alignment in session setup

The handling of unicode string area alignment is wrong.
decode_unicode_ssetup improperly assumes that it will always be preceded
by a pad byte. This isn't the case if the string area is already
word-aligned.

This problem, combined with the bad buffer sizing for the serverDomain
string can cause memory corruption. The bad alignment can make it so
that the alignment of the characters is off. This can make them
translate to characters that are greater than 2 bytes each. If this
happens we can overflow the allocation.

Fix this by fixing the alignment in CIFS_SessSetup instead so we can
verify it against the head of the response. Also, clean up the
workaround for improperly terminated strings by checking for a
odd-length unicode buffers and then forcibly terminating them.

Finally, resize the buffer for serverDomain. Now that we've fixed
the alignment, it's probably fine, but a malicious server could
overflow it.

A better solution for handling these strings is still needed, but
this should be a suitable bandaid.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Steve French <sfrench@us.ibm.com>

authored by Jeff Layton and committed by Steve French 27b87fe5 88dd47ff

+23 -21
+23 -21
fs/cifs/sess.c
··· 285 int words_left, len; 286 char *data = *pbcc_area; 287 288 - 289 - 290 cFYI(1, ("bleft %d", bleft)); 291 292 - 293 - /* SMB header is unaligned, so cifs servers word align start of 294 - Unicode strings */ 295 - data++; 296 - bleft--; /* Windows servers do not always double null terminate 297 - their final Unicode string - in which case we 298 - now will not attempt to decode the byte of junk 299 - which follows it */ 300 301 words_left = bleft / 2; 302 303 /* save off server operating system */ 304 len = UniStrnlen((wchar_t *) data, words_left); 305 306 - /* We look for obvious messed up bcc or strings in response so we do not go off 307 - the end since (at least) WIN2K and Windows XP have a major bug in not null 308 - terminating last Unicode string in response */ 309 if (len >= words_left) 310 return rc; 311 ··· 342 return rc; 343 344 kfree(ses->serverDomain); 345 - ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ 346 - if (ses->serverDomain != NULL) { 347 cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, 348 nls_cp); 349 - ses->serverDomain[2*len] = 0; 350 - ses->serverDomain[(2*len) + 1] = 0; 351 - } 352 data += 2 * (len + 1); 353 words_left -= len + 1; 354 ··· 698 } 699 700 /* BB check if Unicode and decode strings */ 701 - if (smb_buf->Flags2 & SMBFLG2_UNICODE) 702 rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, 703 - ses, nls_cp); 704 - else 705 rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, 706 ses, nls_cp); 707 708 ssetup_exit: 709 if (spnego_key) {
··· 285 int words_left, len; 286 char *data = *pbcc_area; 287 288 cFYI(1, ("bleft %d", bleft)); 289 290 + /* 291 + * Windows servers do not always double null terminate their final 292 + * Unicode string. Check to see if there are an uneven number of bytes 293 + * left. If so, then add an extra NULL pad byte to the end of the 294 + * response. 295 + * 296 + * See section 2.7.2 in "Implementing CIFS" for details 297 + */ 298 + if (bleft % 2) { 299 + data[bleft] = 0; 300 + ++bleft; 301 + } 302 303 words_left = bleft / 2; 304 305 /* save off server operating system */ 306 len = UniStrnlen((wchar_t *) data, words_left); 307 308 if (len >= words_left) 309 return rc; 310 ··· 343 return rc; 344 345 kfree(ses->serverDomain); 346 + ses->serverDomain = kzalloc((4 * len) + 2, GFP_KERNEL); 347 + if (ses->serverDomain != NULL) 348 cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, 349 nls_cp); 350 data += 2 * (len + 1); 351 words_left -= len + 1; 352 ··· 702 } 703 704 /* BB check if Unicode and decode strings */ 705 + if (smb_buf->Flags2 & SMBFLG2_UNICODE) { 706 + /* unicode string area must be word-aligned */ 707 + if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { 708 + ++bcc_ptr; 709 + --bytes_remaining; 710 + } 711 rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, 712 + ses, nls_cp); 713 + } else { 714 rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, 715 ses, nls_cp); 716 + } 717 718 ssetup_exit: 719 if (spnego_key) {