Commit 133672efbc1085f9af990bdc145e1822ea93bcf3

Authored by Steve French
1 parent 9418d5dc9b

[CIFS] Fix buffer overflow if server sends corrupt response to small

request

In SendReceive() function in transport.c - it memcpy's
message payload into a buffer passed via out_buf param. The function
assumes that all buffers are of size (CIFSMaxBufSize +
MAX_CIFS_HDR_SIZE) , unfortunately it is also called with smaller
(MAX_CIFS_SMALL_BUFFER_SIZE) buffers.  There are eight callers
(SMB worker functions) which are primarily affected by this change:

TreeDisconnect, uLogoff, Close, findClose, SetFileSize, SetFileTimes,
Lock and PosixLock

CC: Dave Kleikamp <shaggy@austin.ibm.com>
CC: Przemyslaw Wegrzyn <czajnik@czajsoft.pl>
Acked-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>

Showing 7 changed files with 133 additions and 96 deletions Side-by-side Diff

... ... @@ -471,6 +471,17 @@
471 471 #define CIFS_LARGE_BUFFER 2
472 472 #define CIFS_IOVEC 4 /* array of response buffers */
473 473  
  474 +/* Type of Request to SendReceive2 */
  475 +#define CIFS_STD_OP 0 /* normal request timeout */
  476 +#define CIFS_LONG_OP 1 /* long op (up to 45 sec, oplock time) */
  477 +#define CIFS_VLONG_OP 2 /* sloow op - can take up to 180 seconds */
  478 +#define CIFS_BLOCKING_OP 4 /* operation can block */
  479 +#define CIFS_ASYNC_OP 8 /* do not wait for response */
  480 +#define CIFS_TIMEOUT_MASK 0x00F /* only one of 5 above set in req */
  481 +#define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */
  482 +#define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */
  483 +#define CIFS_NO_RESP 0x040 /* no response buffer required */
  484 +
474 485 /* Security Flags: indicate type of session setup needed */
475 486 #define CIFSSEC_MAY_SIGN 0x00001
476 487 #define CIFSSEC_MAY_NTLM 0x00002
... ... @@ -48,10 +48,11 @@
48 48 struct smb_hdr * /* input */ ,
49 49 struct smb_hdr * /* out */ ,
50 50 int * /* bytes returned */ , const int long_op);
  51 +extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
  52 + struct smb_hdr *in_buf, int flags);
51 53 extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
52 54 struct kvec *, int /* nvec to send */,
53   - int * /* type of buf returned */ , const int long_op,
54   - const int logError /* whether to log status code*/ );
  55 + int * /* type of buf returned */ , const int flags);
55 56 extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
56 57 struct cifsTconInfo *,
57 58 struct smb_hdr * /* input */ ,
... ... @@ -698,9 +698,7 @@
698 698 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
699 699 {
700 700 struct smb_hdr *smb_buffer;
701   - struct smb_hdr *smb_buffer_response; /* BB removeme BB */
702 701 int rc = 0;
703   - int length;
704 702  
705 703 cFYI(1, ("In tree disconnect"));
706 704 /*
707 705  
708 706  
... ... @@ -737,16 +735,12 @@
737 735 if (rc) {
738 736 up(&tcon->tconSem);
739 737 return rc;
740   - } else {
741   - smb_buffer_response = smb_buffer; /* BB removeme BB */
742 738 }
743   - rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
744   - &length, 0);
  739 +
  740 + rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
745 741 if (rc)
746 742 cFYI(1, ("Tree disconnect failed %d", rc));
747 743  
748   - if (smb_buffer)
749   - cifs_small_buf_release(smb_buffer);
750 744 up(&tcon->tconSem);
751 745  
752 746 /* No need to return error on this operation if tid invalidated and
753 747  
... ... @@ -760,10 +754,8 @@
760 754 int
761 755 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
762 756 {
763   - struct smb_hdr *smb_buffer_response;
764 757 LOGOFF_ANDX_REQ *pSMB;
765 758 int rc = 0;
766   - int length;
767 759  
768 760 cFYI(1, ("In SMBLogoff for session disconnect"));
769 761 if (ses)
... ... @@ -782,8 +774,6 @@
782 774 return rc;
783 775 }
784 776  
785   - smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
786   -
787 777 if (ses->server) {
788 778 pSMB->hdr.Mid = GetNextMid(ses->server);
789 779  
... ... @@ -795,8 +785,7 @@
795 785 pSMB->hdr.Uid = ses->Suid;
796 786  
797 787 pSMB->AndXCommand = 0xFF;
798   - rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
799   - smb_buffer_response, &length, 0);
  788 + rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
800 789 if (ses->server) {
801 790 atomic_dec(&ses->server->socketUseCount);
802 791 if (atomic_read(&ses->server->socketUseCount) == 0) {
... ... @@ -807,7 +796,6 @@
807 796 }
808 797 }
809 798 up(&ses->sesSem);
810   - cifs_small_buf_release(pSMB);
811 799  
812 800 /* if session dead then we do not need to do ulogoff,
813 801 since server closed smb session, no sense reporting
... ... @@ -1255,7 +1243,7 @@
1255 1243 pSMB->ByteCount = cpu_to_le16(count);
1256 1244 /* long_op set to 1 to allow for oplock break timeouts */
1257 1245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1258   - (struct smb_hdr *) pSMBr, &bytes_returned, 1);
  1246 + (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1259 1247 cifs_stats_inc(&tcon->num_opens);
1260 1248 if (rc) {
1261 1249 cFYI(1, ("Error in Open = %d", rc));
... ... @@ -1368,7 +1356,7 @@
1368 1356 pSMB->ByteCount = cpu_to_le16(count);
1369 1357 /* long_op set to 1 to allow for oplock break timeouts */
1370 1358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1371   - (struct smb_hdr *) pSMBr, &bytes_returned, 1);
  1359 + (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1372 1360 cifs_stats_inc(&tcon->num_opens);
1373 1361 if (rc) {
1374 1362 cFYI(1, ("Error in Open = %d", rc));
... ... @@ -1446,7 +1434,7 @@
1446 1434 iov[0].iov_base = (char *)pSMB;
1447 1435 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1448 1436 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1449   - &resp_buf_type, 0 /* not long op */, 1 /* log err */ );
  1437 + &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1450 1438 cifs_stats_inc(&tcon->num_reads);
1451 1439 pSMBr = (READ_RSP *)iov[0].iov_base;
1452 1440 if (rc) {
... ... @@ -1665,7 +1653,7 @@
1665 1653  
1666 1654  
1667 1655 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1668   - long_op, 0 /* do not log STATUS code */ );
  1656 + long_op);
1669 1657 cifs_stats_inc(&tcon->num_writes);
1670 1658 if (rc) {
1671 1659 cFYI(1, ("Send error Write2 = %d", rc));
... ... @@ -1707,7 +1695,7 @@
1707 1695 int timeout = 0;
1708 1696 __u16 count;
1709 1697  
1710   - cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
  1698 + cFYI(1, ("CIFSSMBLock timeout %d numLock %d", waitFlag, numLock));
1711 1699 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1712 1700  
1713 1701 if (rc)
1714 1702  
... ... @@ -1716,10 +1704,10 @@
1716 1704 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1717 1705  
1718 1706 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1719   - timeout = -1; /* no response expected */
  1707 + timeout = CIFS_ASYNC_OP; /* no response expected */
1720 1708 pSMB->Timeout = 0;
1721 1709 } else if (waitFlag == TRUE) {
1722   - timeout = 3; /* blocking operation, no timeout */
  1710 + timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1723 1711 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1724 1712 } else {
1725 1713 pSMB->Timeout = 0;
1726 1714  
1727 1715  
... ... @@ -1749,15 +1737,16 @@
1749 1737 if (waitFlag) {
1750 1738 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1751 1739 (struct smb_hdr *) pSMBr, &bytes_returned);
  1740 + cifs_small_buf_release(pSMB);
1752 1741 } else {
1753   - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1754   - (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
  1742 + rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
  1743 + timeout);
  1744 + /* SMB buffer freed by function above */
1755 1745 }
1756 1746 cifs_stats_inc(&tcon->num_locks);
1757 1747 if (rc) {
1758 1748 cFYI(1, ("Send error in Lock = %d", rc));
1759 1749 }
1760   - cifs_small_buf_release(pSMB);
1761 1750  
1762 1751 /* Note: On -EAGAIN error only caller can retry on handle based calls
1763 1752 since file handle passed in no longer valid */
1764 1753  
... ... @@ -1776,7 +1765,9 @@
1776 1765 int rc = 0;
1777 1766 int timeout = 0;
1778 1767 int bytes_returned = 0;
  1768 + int resp_buf_type = 0;
1779 1769 __u16 params, param_offset, offset, byte_count, count;
  1770 + struct kvec iov[1];
1780 1771  
1781 1772 cFYI(1, ("Posix Lock"));
1782 1773  
... ... @@ -1818,7 +1809,7 @@
1818 1809  
1819 1810 parm_data->lock_type = cpu_to_le16(lock_type);
1820 1811 if (waitFlag) {
1821   - timeout = 3; /* blocking operation, no timeout */
  1812 + timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1822 1813 parm_data->lock_flags = cpu_to_le16(1);
1823 1814 pSMB->Timeout = cpu_to_le32(-1);
1824 1815 } else
... ... @@ -1838,8 +1829,13 @@
1838 1829 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1839 1830 (struct smb_hdr *) pSMBr, &bytes_returned);
1840 1831 } else {
1841   - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1842   - (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
  1832 + iov[0].iov_base = (char *)pSMB;
  1833 + iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
  1834 + rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
  1835 + &resp_buf_type, timeout);
  1836 + pSMB = NULL; /* request buf already freed by SendReceive2. Do
  1837 + not try to free it twice below on exit */
  1838 + pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1843 1839 }
1844 1840  
1845 1841 if (rc) {
... ... @@ -1874,6 +1870,11 @@
1874 1870 if (pSMB)
1875 1871 cifs_small_buf_release(pSMB);
1876 1872  
  1873 + if (resp_buf_type == CIFS_SMALL_BUFFER)
  1874 + cifs_small_buf_release(iov[0].iov_base);
  1875 + else if (resp_buf_type == CIFS_LARGE_BUFFER)
  1876 + cifs_buf_release(iov[0].iov_base);
  1877 +
1877 1878 /* Note: On -EAGAIN error only caller can retry on handle based calls
1878 1879 since file handle passed in no longer valid */
1879 1880  
... ... @@ -1886,8 +1887,6 @@
1886 1887 {
1887 1888 int rc = 0;
1888 1889 CLOSE_REQ *pSMB = NULL;
1889   - CLOSE_RSP *pSMBr = NULL;
1890   - int bytes_returned;
1891 1890 cFYI(1, ("In CIFSSMBClose"));
1892 1891  
1893 1892 /* do not retry on dead session on close */
1894 1893  
... ... @@ -1897,13 +1896,10 @@
1897 1896 if (rc)
1898 1897 return rc;
1899 1898  
1900   - pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1901   -
1902 1899 pSMB->FileID = (__u16) smb_file_id;
1903 1900 pSMB->LastWriteTime = 0xFFFFFFFF;
1904 1901 pSMB->ByteCount = 0;
1905   - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1906   - (struct smb_hdr *) pSMBr, &bytes_returned, 0);
  1902 + rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1907 1903 cifs_stats_inc(&tcon->num_closes);
1908 1904 if (rc) {
1909 1905 if (rc != -EINTR) {
... ... @@ -1912,8 +1908,6 @@
1912 1908 }
1913 1909 }
1914 1910  
1915   - cifs_small_buf_release(pSMB);
1916   -
1917 1911 /* Since session is dead, file will be closed on server already */
1918 1912 if (rc == -EAGAIN)
1919 1913 rc = 0;
... ... @@ -3102,7 +3096,7 @@
3102 3096 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3103 3097  
3104 3098 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3105   - 0 /* not long op */, 0 /* do not log STATUS codes */ );
  3099 + CIFS_STD_OP);
3106 3100 cifs_stats_inc(&tcon->num_acl_get);
3107 3101 if (rc) {
3108 3102 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
... ... @@ -3763,8 +3757,6 @@
3763 3757 {
3764 3758 int rc = 0;
3765 3759 FINDCLOSE_REQ *pSMB = NULL;
3766   - CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3767   - int bytes_returned;
3768 3760  
3769 3761 cFYI(1, ("In CIFSSMBFindClose"));
3770 3762 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3771 3763  
3772 3764  
... ... @@ -3776,16 +3768,13 @@
3776 3768 if (rc)
3777 3769 return rc;
3778 3770  
3779   - pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3780 3771 pSMB->FileID = searchHandle;
3781 3772 pSMB->ByteCount = 0;
3782   - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3783   - (struct smb_hdr *) pSMBr, &bytes_returned, 0);
  3773 + rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3784 3774 if (rc) {
3785 3775 cERROR(1, ("Send error in FindClose = %d", rc));
3786 3776 }
3787 3777 cifs_stats_inc(&tcon->num_fclose);
3788   - cifs_small_buf_release(pSMB);
3789 3778  
3790 3779 /* Since session is dead, search handle closed on server already */
3791 3780 if (rc == -EAGAIN)
3792 3781  
... ... @@ -4707,11 +4696,9 @@
4707 4696 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4708 4697 {
4709 4698 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4710   - struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4711 4699 char *data_offset;
4712 4700 struct file_end_of_file_info *parm_data;
4713 4701 int rc = 0;
4714   - int bytes_returned = 0;
4715 4702 __u16 params, param_offset, offset, byte_count, count;
4716 4703  
4717 4704 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
... ... @@ -4721,8 +4708,6 @@
4721 4708 if (rc)
4722 4709 return rc;
4723 4710  
4724   - pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4725   -
4726 4711 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4727 4712 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4728 4713  
4729 4714  
... ... @@ -4773,17 +4758,13 @@
4773 4758 pSMB->Reserved4 = 0;
4774 4759 pSMB->hdr.smb_buf_length += byte_count;
4775 4760 pSMB->ByteCount = cpu_to_le16(byte_count);
4776   - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4777   - (struct smb_hdr *) pSMBr, &bytes_returned, 0);
  4761 + rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4778 4762 if (rc) {
4779 4763 cFYI(1,
4780 4764 ("Send error in SetFileInfo (SetFileSize) = %d",
4781 4765 rc));
4782 4766 }
4783 4767  
4784   - if (pSMB)
4785   - cifs_small_buf_release(pSMB);
4786   -
4787 4768 /* Note: On -EAGAIN error only caller can retry on handle based calls
4788 4769 since file handle passed in no longer valid */
4789 4770  
4790 4771  
... ... @@ -4801,10 +4782,8 @@
4801 4782 const FILE_BASIC_INFO *data, __u16 fid)
4802 4783 {
4803 4784 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4804   - struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4805 4785 char *data_offset;
4806 4786 int rc = 0;
4807   - int bytes_returned = 0;
4808 4787 __u16 params, param_offset, offset, byte_count, count;
4809 4788  
4810 4789 cFYI(1, ("Set Times (via SetFileInfo)"));
... ... @@ -4813,8 +4792,6 @@
4813 4792 if (rc)
4814 4793 return rc;
4815 4794  
4816   - pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4817   -
4818 4795 /* At this point there is no need to override the current pid
4819 4796 with the pid of the opener, but that could change if we someday
4820 4797 use an existing handle (rather than opening one on the fly) */
4821 4798  
... ... @@ -4854,14 +4831,11 @@
4854 4831 pSMB->hdr.smb_buf_length += byte_count;
4855 4832 pSMB->ByteCount = cpu_to_le16(byte_count);
4856 4833 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4857   - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4858   - (struct smb_hdr *) pSMBr, &bytes_returned, 0);
  4834 + rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4859 4835 if (rc) {
4860 4836 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4861 4837 }
4862 4838  
4863   - cifs_small_buf_release(pSMB);
4864   -
4865 4839 /* Note: On -EAGAIN error only caller can retry on handle based calls
4866 4840 since file handle passed in no longer valid */
4867 4841  
... ... @@ -5152,7 +5126,8 @@
5152 5126 pSMB->ByteCount = 0;
5153 5127  
5154 5128 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5155   - (struct smb_hdr *) pSMBr, &bytes_returned, -1);
  5129 + (struct smb_hdr *)pSMBr, &bytes_returned,
  5130 + CIFS_ASYNC_OP);
5156 5131 if (rc) {
5157 5132 cFYI(1, ("Error in Notify = %d", rc));
5158 5133 } else {
... ... @@ -2374,7 +2374,7 @@
2374 2374 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2375 2375  
2376 2376 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2377   - &bytes_returned, 1);
  2377 + &bytes_returned, CIFS_LONG_OP);
2378 2378 if (rc) {
2379 2379 /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2380 2380 } else if ((smb_buffer_response->WordCount == 3)
... ... @@ -2678,7 +2678,7 @@
2678 2678 pSMB->req.ByteCount = cpu_to_le16(count);
2679 2679  
2680 2680 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2681   - &bytes_returned, 1);
  2681 + &bytes_returned, CIFS_LONG_OP);
2682 2682  
2683 2683 if (smb_buffer_response->Status.CifsError ==
2684 2684 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
... ... @@ -3105,7 +3105,7 @@
3105 3105 pSMB->req.ByteCount = cpu_to_le16(count);
3106 3106  
3107 3107 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3108   - &bytes_returned, 1);
  3108 + &bytes_returned, CIFS_LONG_OP);
3109 3109 if (rc) {
3110 3110 /* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3111 3111 } else if ((smb_buffer_response->WordCount == 3) ||
... ... @@ -3381,7 +3381,8 @@
3381 3381 pSMB->hdr.smb_buf_length += count;
3382 3382 pSMB->ByteCount = cpu_to_le16(count);
3383 3383  
3384   - rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
  3384 + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
  3385 + CIFS_STD_OP);
3385 3386  
3386 3387 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3387 3388 /* above now done in SendReceive */
... ... @@ -835,9 +835,9 @@
835 835 xid = GetXid();
836 836  
837 837 if (*poffset > file->f_path.dentry->d_inode->i_size)
838   - long_op = 2; /* writes past end of file can take a long time */
  838 + long_op = CIFS_VLONG_OP; /* writes past EOF take long time */
839 839 else
840   - long_op = 1;
  840 + long_op = CIFS_LONG_OP;
841 841  
842 842 for (total_written = 0; write_size > total_written;
843 843 total_written += bytes_written) {
... ... @@ -884,7 +884,7 @@
884 884 }
885 885 } else
886 886 *poffset += bytes_written;
887   - long_op = FALSE; /* subsequent writes fast -
  887 + long_op = CIFS_STD_OP; /* subsequent writes fast -
888 888 15 seconds is plenty */
889 889 }
890 890  
891 891  
... ... @@ -934,9 +934,9 @@
934 934 xid = GetXid();
935 935  
936 936 if (*poffset > file->f_path.dentry->d_inode->i_size)
937   - long_op = 2; /* writes past end of file can take a long time */
  937 + long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */
938 938 else
939   - long_op = 1;
  939 + long_op = CIFS_LONG_OP;
940 940  
941 941 for (total_written = 0; write_size > total_written;
942 942 total_written += bytes_written) {
... ... @@ -1002,7 +1002,7 @@
1002 1002 }
1003 1003 } else
1004 1004 *poffset += bytes_written;
1005   - long_op = FALSE; /* subsequent writes fast -
  1005 + long_op = CIFS_STD_OP; /* subsequent writes fast -
1006 1006 15 seconds is plenty */
1007 1007 }
1008 1008  
... ... @@ -1360,7 +1360,7 @@
1360 1360 open_file->netfid,
1361 1361 bytes_to_write, offset,
1362 1362 &bytes_written, iov, n_iov,
1363   - 1);
  1363 + CIFS_LONG_OP);
1364 1364 atomic_dec(&open_file->wrtPending);
1365 1365 if (rc || bytes_written < bytes_to_write) {
1366 1366 cERROR(1, ("Write2 ret %d, wrote %d",
... ... @@ -514,7 +514,7 @@
514 514 iov[1].iov_base = str_area;
515 515 iov[1].iov_len = count;
516 516 rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type,
517   - 0 /* not long op */, 1 /* log NT STATUS if any */ );
  517 + CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR);
518 518 /* SMB request buf freed in SendReceive2 */
519 519  
520 520 cFYI(1, ("ssetup rc from sendrecv2 is %d", rc));
... ... @@ -308,7 +308,7 @@
308 308  
309 309 static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
310 310 {
311   - if (long_op == -1) {
  311 + if (long_op == CIFS_ASYNC_OP) {
312 312 /* oplock breaks must not be held up */
313 313 atomic_inc(&ses->server->inFlight);
314 314 } else {
... ... @@ -337,7 +337,7 @@
337 337 as they are allowed to block on server */
338 338  
339 339 /* update # of requests on the wire to server */
340   - if (long_op < 3)
  340 + if (long_op != CIFS_BLOCKING_OP)
341 341 atomic_inc(&ses->server->inFlight);
342 342 spin_unlock(&GlobalMid_Lock);
343 343 break;
344 344  
345 345  
346 346  
347 347  
... ... @@ -415,17 +415,48 @@
415 415 }
416 416 }
417 417  
  418 +
  419 +/*
  420 + *
  421 + * Send an SMB Request. No response info (other than return code)
  422 + * needs to be parsed.
  423 + *
  424 + * flags indicate the type of request buffer and how long to wait
  425 + * and whether to log NT STATUS code (error) before mapping it to POSIX error
  426 + *
  427 + */
418 428 int
  429 +SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
  430 + struct smb_hdr *in_buf, int flags)
  431 +{
  432 + int rc;
  433 + struct kvec iov[1];
  434 + int resp_buf_type;
  435 +
  436 + iov[0].iov_base = (char *)in_buf;
  437 + iov[0].iov_len = in_buf->smb_buf_length + 4;
  438 + flags |= CIFS_NO_RESP;
  439 + rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
  440 +#ifdef CONFIG_CIFS_DEBUG2
  441 + cFYI(1, ("SendRcvNoR flags %d rc %d", flags, rc));
  442 +#endif
  443 + return rc;
  444 +}
  445 +
  446 +int
419 447 SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
420 448 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
421   - const int long_op, const int logError)
  449 + const int flags)
422 450 {
423 451 int rc = 0;
  452 + int long_op;
424 453 unsigned int receive_len;
425 454 unsigned long timeout;
426 455 struct mid_q_entry *midQ;
427 456 struct smb_hdr *in_buf = iov[0].iov_base;
428 457  
  458 + long_op = flags & CIFS_TIMEOUT_MASK;
  459 +
429 460 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
430 461  
431 462 if ((ses == NULL) || (ses->server == NULL)) {
432 463  
433 464  
... ... @@ -483,15 +514,22 @@
483 514 if (rc < 0)
484 515 goto out;
485 516  
486   - if (long_op == -1)
487   - goto out;
488   - else if (long_op == 2) /* writes past end of file can take loong time */
  517 + if (long_op == CIFS_STD_OP)
  518 + timeout = 15 * HZ;
  519 + else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
489 520 timeout = 180 * HZ;
490   - else if (long_op == 1)
  521 + else if (long_op == CIFS_LONG_OP)
491 522 timeout = 45 * HZ; /* should be greater than
492 523 servers oplock break timeout (about 43 seconds) */
493   - else
494   - timeout = 15 * HZ;
  524 + else if (long_op == CIFS_ASYNC_OP)
  525 + goto out;
  526 + else if (long_op == CIFS_BLOCKING_OP)
  527 + timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
  528 + else {
  529 + cERROR(1, ("unknown timeout flag %d", long_op));
  530 + rc = -EIO;
  531 + goto out;
  532 + }
495 533  
496 534 /* wait for 15 seconds or until woken up due to response arriving or
497 535 due to last connection to this server being unmounted */
... ... @@ -566,7 +604,8 @@
566 604 }
567 605  
568 606 /* BB special case reconnect tid and uid here? */
569   - rc = map_smb_to_linux_error(midQ->resp_buf, logError);
  607 + rc = map_smb_to_linux_error(midQ->resp_buf,
  608 + flags & CIFS_LOG_ERROR);
570 609  
571 610 /* convert ByteCount if necessary */
572 611 if (receive_len >= sizeof(struct smb_hdr) - 4
... ... @@ -574,8 +613,10 @@
574 613 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
575 614 BCC(midQ->resp_buf) =
576 615 le16_to_cpu(BCC_LE(midQ->resp_buf));
577   - midQ->resp_buf = NULL; /* mark it so will not be freed
578   - by DeleteMidQEntry */
  616 + if ((flags & CIFS_NO_RESP) == 0)
  617 + midQ->resp_buf = NULL; /* mark it so buf will
  618 + not be freed by
  619 + DeleteMidQEntry */
579 620 } else {
580 621 rc = -EIO;
581 622 cFYI(1, ("Bad MID state?"));
582 623  
583 624  
584 625  
... ... @@ -663,17 +704,25 @@
663 704 if (rc < 0)
664 705 goto out;
665 706  
666   - if (long_op == -1)
  707 + if (long_op == CIFS_STD_OP)
  708 + timeout = 15 * HZ;
  709 + /* wait for 15 seconds or until woken up due to response arriving or
  710 + due to last connection to this server being unmounted */
  711 + else if (long_op == CIFS_ASYNC_OP)
667 712 goto out;
668   - else if (long_op == 2) /* writes past end of file can take loong time */
  713 + else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
669 714 timeout = 180 * HZ;
670   - else if (long_op == 1)
  715 + else if (long_op == CIFS_LONG_OP)
671 716 timeout = 45 * HZ; /* should be greater than
672 717 servers oplock break timeout (about 43 seconds) */
673   - else
674   - timeout = 15 * HZ;
675   - /* wait for 15 seconds or until woken up due to response arriving or
676   - due to last connection to this server being unmounted */
  718 + else if (long_op == CIFS_BLOCKING_OP)
  719 + timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
  720 + else {
  721 + cERROR(1, ("unknown timeout flag %d", long_op));
  722 + rc = -EIO;
  723 + goto out;
  724 + }
  725 +
677 726 if (signal_pending(current)) {
678 727 /* if signal pending do not hold up user for full smb timeout
679 728 but we still give response a chance to complete */
... ... @@ -812,7 +861,7 @@
812 861 pSMB->hdr.Mid = GetNextMid(ses->server);
813 862  
814 863 return SendReceive(xid, ses, in_buf, out_buf,
815   - &bytes_returned, 0);
  864 + &bytes_returned, CIFS_STD_OP);
816 865 }
817 866  
818 867 int
... ... @@ -844,7 +893,7 @@
844 893 to the same server. We may make this configurable later or
845 894 use ses->maxReq */
846 895  
847   - rc = wait_for_free_request(ses, 3);
  896 + rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
848 897 if (rc)
849 898 return rc;
850 899