Skip to content

Commit 4326ed2

Browse files
piastrysmfrench
authored andcommitted
CIFS: Decrypt and process small encrypted packets
Allow to decrypt transformed packets, find a corresponding mid and process as usual further. Signed-off-by: Pavel Shilovsky <[email protected]>
1 parent d70b910 commit 4326ed2

File tree

7 files changed

+243
-3
lines changed

7 files changed

+243
-3
lines changed

fs/cifs/cifsglob.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,6 +1344,7 @@ struct mid_q_entry {
13441344
bool large_buf:1; /* if valid response, is pointer to large buf */
13451345
bool multiRsp:1; /* multiple trans2 responses for one request */
13461346
bool multiEnd:1; /* both received */
1347+
bool decrypted:1; /* decrypted entry */
13471348
};
13481349

13491350
/* Make code in transport.c a little cleaner by moving

fs/cifs/cifsproto.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
7575
extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
7676
extern void cifs_delete_mid(struct mid_q_entry *mid);
7777
extern void cifs_wake_up_task(struct mid_q_entry *mid);
78+
extern int cifs_handle_standard(struct TCP_Server_Info *server,
79+
struct mid_q_entry *mid);
7880
extern int cifs_call_async(struct TCP_Server_Info *server,
7981
struct smb_rqst *rqst,
8082
mid_receive_t *receive, mid_callback_t *callback,

fs/cifs/connect.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,15 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
787787

788788
dump_smb(buf, server->total_read);
789789

790+
return cifs_handle_standard(server, mid);
791+
}
792+
793+
int
794+
cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
795+
{
796+
char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
797+
int length;
798+
790799
/*
791800
* We know that we received enough to get to the MID as we
792801
* checked the pdu_length earlier. Now check to see

fs/cifs/smb2ops.c

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,6 +1799,228 @@ smb3_free_transform_rq(struct smb_rqst *rqst)
17991799
kfree(rqst->rq_iov);
18001800
}
18011801

1802+
static int
1803+
smb3_is_transform_hdr(void *buf)
1804+
{
1805+
struct smb2_transform_hdr *trhdr = buf;
1806+
1807+
return trhdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM;
1808+
}
1809+
1810+
static int
1811+
decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
1812+
unsigned int buf_data_size, struct page **pages,
1813+
unsigned int npages, unsigned int page_data_size)
1814+
{
1815+
struct kvec iov[2];
1816+
struct smb_rqst rqst = {NULL};
1817+
struct smb2_hdr *hdr;
1818+
int rc;
1819+
1820+
iov[0].iov_base = buf;
1821+
iov[0].iov_len = sizeof(struct smb2_transform_hdr);
1822+
iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr);
1823+
iov[1].iov_len = buf_data_size;
1824+
1825+
rqst.rq_iov = iov;
1826+
rqst.rq_nvec = 2;
1827+
rqst.rq_pages = pages;
1828+
rqst.rq_npages = npages;
1829+
rqst.rq_pagesz = PAGE_SIZE;
1830+
rqst.rq_tailsz = (page_data_size % PAGE_SIZE) ? : PAGE_SIZE;
1831+
1832+
rc = crypt_message(server, &rqst, 0);
1833+
cifs_dbg(FYI, "decrypt message returned %d\n", rc);
1834+
1835+
if (rc)
1836+
return rc;
1837+
1838+
memmove(buf + 4, iov[1].iov_base, buf_data_size);
1839+
hdr = (struct smb2_hdr *)buf;
1840+
hdr->smb2_buf_length = cpu_to_be32(buf_data_size + page_data_size);
1841+
server->total_read = buf_data_size + page_data_size + 4;
1842+
1843+
return rc;
1844+
}
1845+
1846+
static int
1847+
handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1848+
char *buf, unsigned int buf_len, struct page **pages,
1849+
unsigned int npages, unsigned int page_data_size)
1850+
{
1851+
unsigned int data_offset;
1852+
unsigned int data_len;
1853+
struct cifs_readdata *rdata = mid->callback_data;
1854+
struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
1855+
struct bio_vec *bvec = NULL;
1856+
struct iov_iter iter;
1857+
struct kvec iov;
1858+
int length;
1859+
1860+
if (shdr->Command != SMB2_READ) {
1861+
cifs_dbg(VFS, "only big read responses are supported\n");
1862+
return -ENOTSUPP;
1863+
}
1864+
1865+
if (server->ops->is_status_pending &&
1866+
server->ops->is_status_pending(buf, server, 0))
1867+
return -1;
1868+
1869+
rdata->result = server->ops->map_error(buf, false);
1870+
if (rdata->result != 0) {
1871+
cifs_dbg(FYI, "%s: server returned error %d\n",
1872+
__func__, rdata->result);
1873+
dequeue_mid(mid, rdata->result);
1874+
return 0;
1875+
}
1876+
1877+
data_offset = server->ops->read_data_offset(buf) + 4;
1878+
data_len = server->ops->read_data_length(buf);
1879+
1880+
if (data_offset < server->vals->read_rsp_size) {
1881+
/*
1882+
* win2k8 sometimes sends an offset of 0 when the read
1883+
* is beyond the EOF. Treat it as if the data starts just after
1884+
* the header.
1885+
*/
1886+
cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1887+
__func__, data_offset);
1888+
data_offset = server->vals->read_rsp_size;
1889+
} else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1890+
/* data_offset is beyond the end of smallbuf */
1891+
cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1892+
__func__, data_offset);
1893+
rdata->result = -EIO;
1894+
dequeue_mid(mid, rdata->result);
1895+
return 0;
1896+
}
1897+
1898+
if (buf_len <= data_offset) {
1899+
/* read response payload is in pages */
1900+
/* BB add code to init iter with pages */
1901+
} else if (buf_len >= data_offset + data_len) {
1902+
/* read response payload is in buf */
1903+
WARN_ONCE(npages > 0, "read data can be either in buf or in pages");
1904+
iov.iov_base = buf + data_offset;
1905+
iov.iov_len = data_len;
1906+
iov_iter_kvec(&iter, WRITE | ITER_KVEC, &iov, 1, data_len);
1907+
} else {
1908+
/* read response payload cannot be in both buf and pages */
1909+
WARN_ONCE(1, "buf can not contain only a part of read data");
1910+
rdata->result = -EIO;
1911+
dequeue_mid(mid, rdata->result);
1912+
return 0;
1913+
}
1914+
1915+
/* set up first iov for signature check */
1916+
rdata->iov[0].iov_base = buf;
1917+
rdata->iov[0].iov_len = 4;
1918+
rdata->iov[1].iov_base = buf + 4;
1919+
rdata->iov[1].iov_len = server->vals->read_rsp_size - 4;
1920+
cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1921+
rdata->iov[0].iov_base, server->vals->read_rsp_size);
1922+
1923+
length = rdata->copy_into_pages(server, rdata, &iter);
1924+
1925+
kfree(bvec);
1926+
1927+
if (length < 0)
1928+
return length;
1929+
1930+
dequeue_mid(mid, false);
1931+
return length;
1932+
}
1933+
1934+
static int
1935+
receive_encrypted_standard(struct TCP_Server_Info *server,
1936+
struct mid_q_entry **mid)
1937+
{
1938+
int length;
1939+
char *buf = server->smallbuf;
1940+
unsigned int pdu_length = get_rfc1002_length(buf);
1941+
unsigned int buf_size;
1942+
struct mid_q_entry *mid_entry;
1943+
1944+
/* switch to large buffer if too big for a small one */
1945+
if (pdu_length + 4 > MAX_CIFS_SMALL_BUFFER_SIZE) {
1946+
server->large_buf = true;
1947+
memcpy(server->bigbuf, buf, server->total_read);
1948+
buf = server->bigbuf;
1949+
}
1950+
1951+
/* now read the rest */
1952+
length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
1953+
pdu_length - HEADER_SIZE(server) + 1 + 4);
1954+
if (length < 0)
1955+
return length;
1956+
server->total_read += length;
1957+
1958+
buf_size = pdu_length + 4 - sizeof(struct smb2_transform_hdr);
1959+
length = decrypt_raw_data(server, buf, buf_size, NULL, 0, 0);
1960+
if (length)
1961+
return length;
1962+
1963+
mid_entry = smb2_find_mid(server, buf);
1964+
if (mid_entry == NULL)
1965+
cifs_dbg(FYI, "mid not found\n");
1966+
else {
1967+
cifs_dbg(FYI, "mid found\n");
1968+
mid_entry->decrypted = true;
1969+
}
1970+
1971+
*mid = mid_entry;
1972+
1973+
if (mid_entry && mid_entry->handle)
1974+
return mid_entry->handle(server, mid_entry);
1975+
1976+
return cifs_handle_standard(server, mid_entry);
1977+
}
1978+
1979+
static int
1980+
smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
1981+
{
1982+
char *buf = server->smallbuf;
1983+
unsigned int pdu_length = get_rfc1002_length(buf);
1984+
struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
1985+
unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
1986+
1987+
if (pdu_length + 4 < sizeof(struct smb2_transform_hdr) +
1988+
sizeof(struct smb2_sync_hdr)) {
1989+
cifs_dbg(VFS, "Transform message is too small (%u)\n",
1990+
pdu_length);
1991+
cifs_reconnect(server);
1992+
wake_up(&server->response_q);
1993+
return -ECONNABORTED;
1994+
}
1995+
1996+
if (pdu_length + 4 < orig_len + sizeof(struct smb2_transform_hdr)) {
1997+
cifs_dbg(VFS, "Transform message is broken\n");
1998+
cifs_reconnect(server);
1999+
wake_up(&server->response_q);
2000+
return -ECONNABORTED;
2001+
}
2002+
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+
}
2011+
2012+
return receive_encrypted_standard(server, mid);
2013+
}
2014+
2015+
int
2016+
smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid)
2017+
{
2018+
char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
2019+
2020+
return handle_read_data(server, mid, buf, get_rfc1002_length(buf) + 4,
2021+
NULL, 0, 0);
2022+
}
2023+
18022024
struct smb_version_operations smb20_operations = {
18032025
.compare_fids = smb2_compare_fids,
18042026
.setup_request = smb2_setup_request,
@@ -2047,6 +2269,8 @@ struct smb_version_operations smb30_operations = {
20472269
.enum_snapshots = smb3_enum_snapshots,
20482270
.init_transform_rq = smb3_init_transform_rq,
20492271
.free_transform_rq = smb3_free_transform_rq,
2272+
.is_transform_hdr = smb3_is_transform_hdr,
2273+
.receive_transform = smb3_receive_transform,
20502274
};
20512275

20522276
#ifdef CONFIG_CIFS_SMB311
@@ -2137,6 +2361,8 @@ struct smb_version_operations smb311_operations = {
21372361
.enum_snapshots = smb3_enum_snapshots,
21382362
.init_transform_rq = smb3_init_transform_rq,
21392363
.free_transform_rq = smb3_free_transform_rq,
2364+
.is_transform_hdr = smb3_is_transform_hdr,
2365+
.receive_transform = smb3_receive_transform,
21402366
};
21412367
#endif /* CIFS_SMB311 */
21422368

fs/cifs/smb2pdu.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2281,7 +2281,7 @@ smb2_readv_callback(struct mid_q_entry *mid)
22812281
case MID_RESPONSE_RECEIVED:
22822282
credits_received = le16_to_cpu(shdr->CreditRequest);
22832283
/* result already set, check signature */
2284-
if (server->sign) {
2284+
if (server->sign && !mid->decrypted) {
22852285
int rc;
22862286

22872287
rc = smb2_verify_signature(&rqst, server);
@@ -2384,7 +2384,7 @@ smb2_async_readv(struct cifs_readdata *rdata)
23842384
kref_get(&rdata->refcount);
23852385
rc = cifs_call_async(io_parms.tcon->ses->server, &rqst,
23862386
cifs_readv_receive, smb2_readv_callback,
2387-
NULL, rdata, flags);
2387+
smb3_handle_read_data, rdata, flags);
23882388
if (rc) {
23892389
kref_put(&rdata->refcount, cifs_readdata_release);
23902390
cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE);

fs/cifs/smb2proto.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ extern bool smb2_is_valid_oplock_break(char *buffer,
5858
struct TCP_Server_Info *srv);
5959
extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
6060
__u64 ses_id);
61+
extern int smb3_handle_read_data(struct TCP_Server_Info *server,
62+
struct mid_q_entry *mid);
6163

6264
extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
6365
struct smb2_file_all_info *src);

fs/cifs/smb2transport.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
564564

565565
dump_smb(mid->resp_buf, min_t(u32, 80, len));
566566
/* convert the length into a more usable form */
567-
if (len > 24 && server->sign) {
567+
if (len > 24 && server->sign && !mid->decrypted) {
568568
int rc;
569569

570570
rc = smb2_verify_signature(&rqst, server);

0 commit comments

Comments
 (0)