diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 54 |
1 files changed, 25 insertions, 29 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 37113450757b..675041a6949c 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -331,37 +331,35 @@ smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
331 | 331 | ||
332 | static int validate_t2(struct smb_t2_rsp *pSMB) | 332 | static int validate_t2(struct smb_t2_rsp *pSMB) |
333 | { | 333 | { |
334 | int rc = -EINVAL; | 334 | unsigned int total_size; |
335 | int total_size; | 335 | |
336 | char *pBCC; | 336 | /* check for plausible wct */ |
337 | if (pSMB->hdr.WordCount < 10) | ||
338 | goto vt2_err; | ||
337 | 339 | ||
338 | /* check for plausible wct, bcc and t2 data and parm sizes */ | ||
339 | /* check for parm and data offset going beyond end of smb */ | 340 | /* check for parm and data offset going beyond end of smb */ |
340 | if (pSMB->hdr.WordCount >= 10) { | 341 | if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 || |
341 | if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) && | 342 | get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024) |
342 | (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) { | 343 | goto vt2_err; |
343 | /* check that bcc is at least as big as parms + data */ | 344 | |
344 | /* check that bcc is less than negotiated smb buffer */ | 345 | /* check that bcc is at least as big as parms + data */ |
345 | total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount); | 346 | /* check that bcc is less than negotiated smb buffer */ |
346 | if (total_size < 512) { | 347 | total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount); |
347 | total_size += | 348 | if (total_size >= 512) |
348 | le16_to_cpu(pSMB->t2_rsp.DataCount); | 349 | goto vt2_err; |
349 | /* BCC le converted in SendReceive */ | 350 | |
350 | pBCC = (pSMB->hdr.WordCount * 2) + | 351 | total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount); |
351 | sizeof(struct smb_hdr) + | 352 | if (total_size > get_bcc(&pSMB->hdr) || |
352 | (char *)pSMB; | 353 | total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) |
353 | if ((total_size <= (*(u16 *)pBCC)) && | 354 | goto vt2_err; |
354 | (total_size < | 355 | |
355 | CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) { | 356 | return 0; |
356 | return 0; | 357 | vt2_err: |
357 | } | ||
358 | } | ||
359 | } | ||
360 | } | ||
361 | cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, | 358 | cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, |
362 | sizeof(struct smb_t2_rsp) + 16); | 359 | sizeof(struct smb_t2_rsp) + 16); |
363 | return rc; | 360 | return -EINVAL; |
364 | } | 361 | } |
362 | |||
365 | int | 363 | int |
366 | CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | 364 | CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) |
367 | { | 365 | { |
@@ -452,7 +450,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
452 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), | 450 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), |
453 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 451 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
454 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); | 452 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); |
455 | GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey); | ||
456 | /* even though we do not use raw we might as well set this | 453 | /* even though we do not use raw we might as well set this |
457 | accurately, in case we ever find a need for it */ | 454 | accurately, in case we ever find a need for it */ |
458 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | 455 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { |
@@ -566,7 +563,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
566 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 563 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
567 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); | 564 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); |
568 | cFYI(DBG2, "Max buf = %d", ses->server->maxBuf); | 565 | cFYI(DBG2, "Max buf = %d", ses->server->maxBuf); |
569 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); | ||
570 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | 566 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); |
571 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); | 567 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); |
572 | server->timeAdj *= 60; | 568 | server->timeAdj *= 60; |
@@ -5611,7 +5607,7 @@ QAllEAsRetry: | |||
5611 | } | 5607 | } |
5612 | 5608 | ||
5613 | /* make sure list_len doesn't go past end of SMB */ | 5609 | /* make sure list_len doesn't go past end of SMB */ |
5614 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr); | 5610 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr); |
5615 | if ((char *)ea_response_data + list_len > end_of_smb) { | 5611 | if ((char *)ea_response_data + list_len > end_of_smb) { |
5616 | cFYI(1, "EA list appears to go beyond SMB"); | 5612 | cFYI(1, "EA list appears to go beyond SMB"); |
5617 | rc = -EIO; | 5613 | rc = -EIO; |