Skip to content

Commit c42a6ab

Browse files
piastrysmfrench
authored andcommitted
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 <[email protected]>
1 parent 4326ed2 commit c42a6ab

File tree

3 files changed

+169
-13
lines changed

3 files changed

+169
-13
lines changed

fs/cifs/cifsproto.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ extern void cifs_delete_mid(struct mid_q_entry *mid);
7777
extern void cifs_wake_up_task(struct mid_q_entry *mid);
7878
extern int cifs_handle_standard(struct TCP_Server_Info *server,
7979
struct mid_q_entry *mid);
80+
extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
8081
extern int cifs_call_async(struct TCP_Server_Info *server,
8182
struct smb_rqst *rqst,
8283
mid_receive_t *receive, mid_callback_t *callback,

fs/cifs/cifssmb.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,8 +1399,8 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
13991399
* Discard any remaining data in the current SMB. To do this, we borrow the
14001400
* current bigbuf.
14011401
*/
1402-
static int
1403-
discard_remaining_data(struct TCP_Server_Info *server)
1402+
int
1403+
cifs_discard_remaining_data(struct TCP_Server_Info *server)
14041404
{
14051405
unsigned int rfclen = get_rfc1002_length(server->smallbuf);
14061406
int remaining = rfclen + 4 - server->total_read;
@@ -1426,7 +1426,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
14261426
int length;
14271427
struct cifs_readdata *rdata = mid->callback_data;
14281428

1429-
length = discard_remaining_data(server);
1429+
length = cifs_discard_remaining_data(server);
14301430
dequeue_mid(mid, rdata->result);
14311431
return length;
14321432
}
@@ -1459,7 +1459,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
14591459

14601460
if (server->ops->is_status_pending &&
14611461
server->ops->is_status_pending(buf, server, 0)) {
1462-
discard_remaining_data(server);
1462+
cifs_discard_remaining_data(server);
14631463
return -1;
14641464
}
14651465

fs/cifs/smb2ops.c

Lines changed: 164 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,13 +1843,73 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
18431843
return rc;
18441844
}
18451845

1846+
static int
1847+
read_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+
1875+
static int
1876+
init_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+
18461903
static int
18471904
handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
18481905
char *buf, unsigned int buf_len, struct page **pages,
18491906
unsigned int npages, unsigned int page_data_size)
18501907
{
18511908
unsigned int data_offset;
18521909
unsigned int data_len;
1910+
unsigned int cur_off;
1911+
unsigned int cur_page_idx;
1912+
unsigned int pad_len;
18531913
struct cifs_readdata *rdata = mid->callback_data;
18541914
struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
18551915
struct bio_vec *bvec = NULL;
@@ -1895,9 +1955,37 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
18951955
return 0;
18961956
}
18971957

1958+
pad_len = data_offset - server->vals->read_rsp_size;
1959+
18981960
if (buf_len <= data_offset) {
18991961
/* 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);
19011989
} else if (buf_len >= data_offset + data_len) {
19021990
/* read response payload is in buf */
19031991
WARN_ONCE(npages > 0, "read data can be either in buf or in pages");
@@ -1931,6 +2019,79 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
19312019
return length;
19322020
}
19332021

2022+
static int
2023+
receive_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+
2085+
free_pages:
2086+
for (i = i - 1; i >= 0; i--)
2087+
put_page(pages[i]);
2088+
kfree(pages);
2089+
return rc;
2090+
discard_data:
2091+
cifs_discard_remaining_data(server);
2092+
goto free_pages;
2093+
}
2094+
19342095
static int
19352096
receive_encrypted_standard(struct TCP_Server_Info *server,
19362097
struct mid_q_entry **mid)
@@ -2000,14 +2161,8 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
20002161
return -ECONNABORTED;
20012162
}
20022163

2003-
if (pdu_length + 4 > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) {
2004-
cifs_dbg(VFS, "Decoding responses of big size (%u) is not supported\n",
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-
}
2164+
if (pdu_length + 4 > CIFSMaxBufSize + MAX_HEADER_SIZE(server))
2165+
return receive_encrypted_read(server, mid);
20112166

20122167
return receive_encrypted_standard(server, mid);
20132168
}

0 commit comments

Comments
 (0)