diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 113 |
1 files changed, 79 insertions, 34 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 2f6795e524d3..3106f5e5c633 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; |
@@ -706,6 +702,53 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | |||
706 | return rc; | 702 | return rc; |
707 | } | 703 | } |
708 | 704 | ||
705 | /* | ||
706 | * This is a no-op for now. We're not really interested in the reply, but | ||
707 | * rather in the fact that the server sent one and that server->lstrp | ||
708 | * gets updated. | ||
709 | * | ||
710 | * FIXME: maybe we should consider checking that the reply matches request? | ||
711 | */ | ||
712 | static void | ||
713 | cifs_echo_callback(struct mid_q_entry *mid) | ||
714 | { | ||
715 | struct TCP_Server_Info *server = mid->callback_data; | ||
716 | |||
717 | DeleteMidQEntry(mid); | ||
718 | atomic_dec(&server->inFlight); | ||
719 | wake_up(&server->request_q); | ||
720 | } | ||
721 | |||
722 | int | ||
723 | CIFSSMBEcho(struct TCP_Server_Info *server) | ||
724 | { | ||
725 | ECHO_REQ *smb; | ||
726 | int rc = 0; | ||
727 | |||
728 | cFYI(1, "In echo request"); | ||
729 | |||
730 | rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb); | ||
731 | if (rc) | ||
732 | return rc; | ||
733 | |||
734 | /* set up echo request */ | ||
735 | smb->hdr.Tid = cpu_to_le16(0xffff); | ||
736 | smb->hdr.WordCount = 1; | ||
737 | put_unaligned_le16(1, &smb->EchoCount); | ||
738 | put_bcc_le(1, &smb->hdr); | ||
739 | smb->Data[0] = 'a'; | ||
740 | smb->hdr.smb_buf_length += 3; | ||
741 | |||
742 | rc = cifs_call_async(server, (struct smb_hdr *)smb, | ||
743 | cifs_echo_callback, server); | ||
744 | if (rc) | ||
745 | cFYI(1, "Echo request failed: %d", rc); | ||
746 | |||
747 | cifs_small_buf_release(smb); | ||
748 | |||
749 | return rc; | ||
750 | } | ||
751 | |||
709 | int | 752 | int |
710 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | 753 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) |
711 | { | 754 | { |
@@ -1193,7 +1236,7 @@ OldOpenRetry: | |||
1193 | pSMB->ByteCount = cpu_to_le16(count); | 1236 | pSMB->ByteCount = cpu_to_le16(count); |
1194 | /* long_op set to 1 to allow for oplock break timeouts */ | 1237 | /* long_op set to 1 to allow for oplock break timeouts */ |
1195 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1238 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1196 | (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); | 1239 | (struct smb_hdr *)pSMBr, &bytes_returned, 0); |
1197 | cifs_stats_inc(&tcon->num_opens); | 1240 | cifs_stats_inc(&tcon->num_opens); |
1198 | if (rc) { | 1241 | if (rc) { |
1199 | cFYI(1, "Error in Open = %d", rc); | 1242 | cFYI(1, "Error in Open = %d", rc); |
@@ -1306,7 +1349,7 @@ openRetry: | |||
1306 | pSMB->ByteCount = cpu_to_le16(count); | 1349 | pSMB->ByteCount = cpu_to_le16(count); |
1307 | /* long_op set to 1 to allow for oplock break timeouts */ | 1350 | /* long_op set to 1 to allow for oplock break timeouts */ |
1308 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1351 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1309 | (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); | 1352 | (struct smb_hdr *)pSMBr, &bytes_returned, 0); |
1310 | cifs_stats_inc(&tcon->num_opens); | 1353 | cifs_stats_inc(&tcon->num_opens); |
1311 | if (rc) { | 1354 | if (rc) { |
1312 | cFYI(1, "Error in Open = %d", rc); | 1355 | cFYI(1, "Error in Open = %d", rc); |
@@ -1388,7 +1431,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, | |||
1388 | iov[0].iov_base = (char *)pSMB; | 1431 | iov[0].iov_base = (char *)pSMB; |
1389 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 1432 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
1390 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, | 1433 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, |
1391 | &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR); | 1434 | &resp_buf_type, CIFS_LOG_ERROR); |
1392 | cifs_stats_inc(&tcon->num_reads); | 1435 | cifs_stats_inc(&tcon->num_reads); |
1393 | pSMBr = (READ_RSP *)iov[0].iov_base; | 1436 | pSMBr = (READ_RSP *)iov[0].iov_base; |
1394 | if (rc) { | 1437 | if (rc) { |
@@ -1663,7 +1706,8 @@ int | |||
1663 | CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | 1706 | CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, |
1664 | const __u16 smb_file_id, const __u64 len, | 1707 | const __u16 smb_file_id, const __u64 len, |
1665 | const __u64 offset, const __u32 numUnlock, | 1708 | const __u64 offset, const __u32 numUnlock, |
1666 | const __u32 numLock, const __u8 lockType, const bool waitFlag) | 1709 | const __u32 numLock, const __u8 lockType, |
1710 | const bool waitFlag, const __u8 oplock_level) | ||
1667 | { | 1711 | { |
1668 | int rc = 0; | 1712 | int rc = 0; |
1669 | LOCK_REQ *pSMB = NULL; | 1713 | LOCK_REQ *pSMB = NULL; |
@@ -1691,6 +1735,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
1691 | pSMB->NumberOfLocks = cpu_to_le16(numLock); | 1735 | pSMB->NumberOfLocks = cpu_to_le16(numLock); |
1692 | pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); | 1736 | pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); |
1693 | pSMB->LockType = lockType; | 1737 | pSMB->LockType = lockType; |
1738 | pSMB->OplockLevel = oplock_level; | ||
1694 | pSMB->AndXCommand = 0xFF; /* none */ | 1739 | pSMB->AndXCommand = 0xFF; /* none */ |
1695 | pSMB->Fid = smb_file_id; /* netfid stays le */ | 1740 | pSMB->Fid = smb_file_id; /* netfid stays le */ |
1696 | 1741 | ||
@@ -3087,7 +3132,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, | |||
3087 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 3132 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
3088 | 3133 | ||
3089 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, | 3134 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, |
3090 | CIFS_STD_OP); | 3135 | 0); |
3091 | cifs_stats_inc(&tcon->num_acl_get); | 3136 | cifs_stats_inc(&tcon->num_acl_get); |
3092 | if (rc) { | 3137 | if (rc) { |
3093 | cFYI(1, "Send error in QuerySecDesc = %d", rc); | 3138 | cFYI(1, "Send error in QuerySecDesc = %d", rc); |
@@ -5562,7 +5607,7 @@ QAllEAsRetry: | |||
5562 | } | 5607 | } |
5563 | 5608 | ||
5564 | /* make sure list_len doesn't go past end of SMB */ | 5609 | /* make sure list_len doesn't go past end of SMB */ |
5565 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr); | 5610 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr); |
5566 | if ((char *)ea_response_data + list_len > end_of_smb) { | 5611 | if ((char *)ea_response_data + list_len > end_of_smb) { |
5567 | cFYI(1, "EA list appears to go beyond SMB"); | 5612 | cFYI(1, "EA list appears to go beyond SMB"); |
5568 | rc = -EIO; | 5613 | rc = -EIO; |