aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/sess.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2009-04-14 11:00:53 -0400
committerSteve French <sfrench@us.ibm.com>2009-04-16 21:26:50 -0400
commit27b87fe52baba0a55e9723030e76fce94fabcea4 (patch)
treefe1d0b6e29134e4b3160629953a37faf84c0ee17 /fs/cifs/sess.c
parent88dd47fff4891545bfcfdf39146dde8380771766 (diff)
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>
Diffstat (limited to 'fs/cifs/sess.c')
-rw-r--r--fs/cifs/sess.c44
1 files changed, 23 insertions, 21 deletions
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 5c68b4282be9..70d04d08293b 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -285,27 +285,26 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft,
285 int words_left, len; 285 int words_left, len;
286 char *data = *pbcc_area; 286 char *data = *pbcc_area;
287 287
288
289
290 cFYI(1, ("bleft %d", bleft)); 288 cFYI(1, ("bleft %d", bleft));
291 289
292 290 /*
293 /* SMB header is unaligned, so cifs servers word align start of 291 * Windows servers do not always double null terminate their final
294 Unicode strings */ 292 * Unicode string. Check to see if there are an uneven number of bytes
295 data++; 293 * left. If so, then add an extra NULL pad byte to the end of the
296 bleft--; /* Windows servers do not always double null terminate 294 * response.
297 their final Unicode string - in which case we 295 *
298 now will not attempt to decode the byte of junk 296 * See section 2.7.2 in "Implementing CIFS" for details
299 which follows it */ 297 */
298 if (bleft % 2) {
299 data[bleft] = 0;
300 ++bleft;
301 }
300 302
301 words_left = bleft / 2; 303 words_left = bleft / 2;
302 304
303 /* save off server operating system */ 305 /* save off server operating system */
304 len = UniStrnlen((wchar_t *) data, words_left); 306 len = UniStrnlen((wchar_t *) data, words_left);
305 307
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) 308 if (len >= words_left)
310 return rc; 309 return rc;
311 310
@@ -343,13 +342,10 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft,
343 return rc; 342 return rc;
344 343
345 kfree(ses->serverDomain); 344 kfree(ses->serverDomain);
346 ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ 345 ses->serverDomain = kzalloc((4 * len) + 2, GFP_KERNEL);
347 if (ses->serverDomain != NULL) { 346 if (ses->serverDomain != NULL)
348 cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, 347 cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
349 nls_cp); 348 nls_cp);
350 ses->serverDomain[2*len] = 0;
351 ses->serverDomain[(2*len) + 1] = 0;
352 }
353 data += 2 * (len + 1); 349 data += 2 * (len + 1);
354 words_left -= len + 1; 350 words_left -= len + 1;
355 351
@@ -702,12 +698,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
702 } 698 }
703 699
704 /* BB check if Unicode and decode strings */ 700 /* BB check if Unicode and decode strings */
705 if (smb_buf->Flags2 & SMBFLG2_UNICODE) 701 if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
702 /* unicode string area must be word-aligned */
703 if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) {
704 ++bcc_ptr;
705 --bytes_remaining;
706 }
706 rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, 707 rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
707 ses, nls_cp); 708 ses, nls_cp);
708 else 709 } else {
709 rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, 710 rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining,
710 ses, nls_cp); 711 ses, nls_cp);
712 }
711 713
712ssetup_exit: 714ssetup_exit:
713 if (spnego_key) { 715 if (spnego_key) {