aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilov@microsoft.com>2016-11-17 19:20:23 -0500
committerSteve French <smfrench@gmail.com>2017-02-01 17:46:37 -0500
commitc42a6abe3012832a68a371dabe17c2ced97e62ad (patch)
tree246468bd79c68f8d08b6e1c0499af332e20b48e7
parent4326ed2f6a16ae9d33e4209b540dc9a371aba840 (diff)
CIFS: Add capability to decrypt big read responses
Allow to decrypt transformed packets that are bigger than the big buffer size. In particular it is used for read responses that can only exceed the big buffer size. Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
-rw-r--r--fs/cifs/cifsproto.h1
-rw-r--r--fs/cifs/cifssmb.c8
-rw-r--r--fs/cifs/smb2ops.c173
3 files changed, 169 insertions, 13 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 0cca61cb7088..406d2c10ba78 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -77,6 +77,7 @@ extern void cifs_delete_mid(struct mid_q_entry *mid);
77extern void cifs_wake_up_task(struct mid_q_entry *mid); 77extern void cifs_wake_up_task(struct mid_q_entry *mid);
78extern int cifs_handle_standard(struct TCP_Server_Info *server, 78extern int cifs_handle_standard(struct TCP_Server_Info *server,
79 struct mid_q_entry *mid); 79 struct mid_q_entry *mid);
80extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
80extern int cifs_call_async(struct TCP_Server_Info *server, 81extern int cifs_call_async(struct TCP_Server_Info *server,
81 struct smb_rqst *rqst, 82 struct smb_rqst *rqst,
82 mid_receive_t *receive, mid_callback_t *callback, 83 mid_receive_t *receive, mid_callback_t *callback,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index d4b92e33d50c..f5099fb8a22f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1399,8 +1399,8 @@ openRetry:
1399 * Discard any remaining data in the current SMB. To do this, we borrow the 1399 * Discard any remaining data in the current SMB. To do this, we borrow the
1400 * current bigbuf. 1400 * current bigbuf.
1401 */ 1401 */
1402static int 1402int
1403discard_remaining_data(struct TCP_Server_Info *server) 1403cifs_discard_remaining_data(struct TCP_Server_Info *server)
1404{ 1404{
1405 unsigned int rfclen = get_rfc1002_length(server->smallbuf); 1405 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
1406 int remaining = rfclen + 4 - server->total_read; 1406 int remaining = rfclen + 4 - server->total_read;
@@ -1426,7 +1426,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1426 int length; 1426 int length;
1427 struct cifs_readdata *rdata = mid->callback_data; 1427 struct cifs_readdata *rdata = mid->callback_data;
1428 1428
1429 length = discard_remaining_data(server); 1429 length = cifs_discard_remaining_data(server);
1430 dequeue_mid(mid, rdata->result); 1430 dequeue_mid(mid, rdata->result);
1431 return length; 1431 return length;
1432} 1432}
@@ -1459,7 +1459,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1459 1459
1460 if (server->ops->is_status_pending && 1460 if (server->ops->is_status_pending &&
1461 server->ops->is_status_pending(buf, server, 0)) { 1461 server->ops->is_status_pending(buf, server, 0)) {
1462 discard_remaining_data(server); 1462 cifs_discard_remaining_data(server);
1463 return -1; 1463 return -1;
1464 } 1464 }
1465 1465
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 989bb3175091..a44b4dbe4aae 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -1844,12 +1844,72 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
1844} 1844}
1845 1845
1846static int 1846static int
1847read_data_into_pages(struct TCP_Server_Info *server, struct page **pages,
1848 unsigned int npages, unsigned int len)
1849{
1850 int i;
1851 int length;
1852
1853 for (i = 0; i < npages; i++) {
1854 struct page *page = pages[i];
1855 size_t n;
1856
1857 n = len;
1858 if (len >= PAGE_SIZE) {
1859 /* enough data to fill the page */
1860 n = PAGE_SIZE;
1861 len -= n;
1862 } else {
1863 zero_user(page, len, PAGE_SIZE - len);
1864 len = 0;
1865 }
1866 length = cifs_read_page_from_socket(server, page, n);
1867 if (length < 0)
1868 return length;
1869 server->total_read += length;
1870 }
1871
1872 return 0;
1873}
1874
1875static int
1876init_read_bvec(struct page **pages, unsigned int npages, unsigned int data_size,
1877 unsigned int cur_off, struct bio_vec **page_vec)
1878{
1879 struct bio_vec *bvec;
1880 int i;
1881
1882 bvec = kcalloc(npages, sizeof(struct bio_vec), GFP_KERNEL);
1883 if (!bvec)
1884 return -ENOMEM;
1885
1886 for (i = 0; i < npages; i++) {
1887 bvec[i].bv_page = pages[i];
1888 bvec[i].bv_offset = (i == 0) ? cur_off : 0;
1889 bvec[i].bv_len = min_t(unsigned int, PAGE_SIZE, data_size);
1890 data_size -= bvec[i].bv_len;
1891 }
1892
1893 if (data_size != 0) {
1894 cifs_dbg(VFS, "%s: something went wrong\n", __func__);
1895 kfree(bvec);
1896 return -EIO;
1897 }
1898
1899 *page_vec = bvec;
1900 return 0;
1901}
1902
1903static int
1847handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, 1904handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1848 char *buf, unsigned int buf_len, struct page **pages, 1905 char *buf, unsigned int buf_len, struct page **pages,
1849 unsigned int npages, unsigned int page_data_size) 1906 unsigned int npages, unsigned int page_data_size)
1850{ 1907{
1851 unsigned int data_offset; 1908 unsigned int data_offset;
1852 unsigned int data_len; 1909 unsigned int data_len;
1910 unsigned int cur_off;
1911 unsigned int cur_page_idx;
1912 unsigned int pad_len;
1853 struct cifs_readdata *rdata = mid->callback_data; 1913 struct cifs_readdata *rdata = mid->callback_data;
1854 struct smb2_sync_hdr *shdr = get_sync_hdr(buf); 1914 struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
1855 struct bio_vec *bvec = NULL; 1915 struct bio_vec *bvec = NULL;
@@ -1895,9 +1955,37 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1895 return 0; 1955 return 0;
1896 } 1956 }
1897 1957
1958 pad_len = data_offset - server->vals->read_rsp_size;
1959
1898 if (buf_len <= data_offset) { 1960 if (buf_len <= data_offset) {
1899 /* read response payload is in pages */ 1961 /* read response payload is in pages */
1900 /* BB add code to init iter with pages */ 1962 cur_page_idx = pad_len / PAGE_SIZE;
1963 cur_off = pad_len % PAGE_SIZE;
1964
1965 if (cur_page_idx != 0) {
1966 /* data offset is beyond the 1st page of response */
1967 cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
1968 __func__, data_offset);
1969 rdata->result = -EIO;
1970 dequeue_mid(mid, rdata->result);
1971 return 0;
1972 }
1973
1974 if (data_len > page_data_size - pad_len) {
1975 /* data_len is corrupt -- discard frame */
1976 rdata->result = -EIO;
1977 dequeue_mid(mid, rdata->result);
1978 return 0;
1979 }
1980
1981 rdata->result = init_read_bvec(pages, npages, page_data_size,
1982 cur_off, &bvec);
1983 if (rdata->result != 0) {
1984 dequeue_mid(mid, rdata->result);
1985 return 0;
1986 }
1987
1988 iov_iter_bvec(&iter, WRITE | ITER_BVEC, bvec, npages, data_len);
1901 } else if (buf_len >= data_offset + data_len) { 1989 } else if (buf_len >= data_offset + data_len) {
1902 /* read response payload is in buf */ 1990 /* read response payload is in buf */
1903 WARN_ONCE(npages > 0, "read data can be either in buf or in pages"); 1991 WARN_ONCE(npages > 0, "read data can be either in buf or in pages");
@@ -1932,6 +2020,79 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1932} 2020}
1933 2021
1934static int 2022static int
2023receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
2024{
2025 char *buf = server->smallbuf;
2026 struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
2027 unsigned int npages;
2028 struct page **pages;
2029 unsigned int len;
2030 unsigned int buflen = get_rfc1002_length(buf) + 4;
2031 int rc;
2032 int i = 0;
2033
2034 len = min_t(unsigned int, buflen, server->vals->read_rsp_size - 4 +
2035 sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
2036
2037 rc = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, len);
2038 if (rc < 0)
2039 return rc;
2040 server->total_read += rc;
2041
2042 len = le32_to_cpu(tr_hdr->OriginalMessageSize) + 4 -
2043 server->vals->read_rsp_size;
2044 npages = DIV_ROUND_UP(len, PAGE_SIZE);
2045
2046 pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
2047 if (!pages) {
2048 rc = -ENOMEM;
2049 goto discard_data;
2050 }
2051
2052 for (; i < npages; i++) {
2053 pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
2054 if (!pages[i]) {
2055 rc = -ENOMEM;
2056 goto discard_data;
2057 }
2058 }
2059
2060 /* read read data into pages */
2061 rc = read_data_into_pages(server, pages, npages, len);
2062 if (rc)
2063 goto free_pages;
2064
2065 rc = cifs_discard_remaining_data(server);
2066 if (rc)
2067 goto free_pages;
2068
2069 rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size - 4,
2070 pages, npages, len);
2071 if (rc)
2072 goto free_pages;
2073
2074 *mid = smb2_find_mid(server, buf);
2075 if (*mid == NULL)
2076 cifs_dbg(FYI, "mid not found\n");
2077 else {
2078 cifs_dbg(FYI, "mid found\n");
2079 (*mid)->decrypted = true;
2080 rc = handle_read_data(server, *mid, buf,
2081 server->vals->read_rsp_size,
2082 pages, npages, len);
2083 }
2084
2085free_pages:
2086 for (i = i - 1; i >= 0; i--)
2087 put_page(pages[i]);
2088 kfree(pages);
2089 return rc;
2090discard_data:
2091 cifs_discard_remaining_data(server);
2092 goto free_pages;
2093}
2094
2095static int
1935receive_encrypted_standard(struct TCP_Server_Info *server, 2096receive_encrypted_standard(struct TCP_Server_Info *server,
1936 struct mid_q_entry **mid) 2097 struct mid_q_entry **mid)
1937{ 2098{
@@ -2000,14 +2161,8 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
2000 return -ECONNABORTED; 2161 return -ECONNABORTED;
2001 } 2162 }
2002 2163
2003 if (pdu_length + 4 > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) { 2164 if (pdu_length + 4 > CIFSMaxBufSize + MAX_HEADER_SIZE(server))
2004 cifs_dbg(VFS, "Decoding responses of big size (%u) is not supported\n", 2165 return receive_encrypted_read(server, mid);
2005 pdu_length);
2006 /* BB add code to allocate and fill highmem pages here */
2007 cifs_reconnect(server);
2008 wake_up(&server->response_q);
2009 return -ECONNABORTED;
2010 }
2011 2166
2012 return receive_encrypted_standard(server, mid); 2167 return receive_encrypted_standard(server, mid);
2013} 2168}