aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <paulo@paulo.ac>2018-06-15 09:22:44 -0400
committerSteve French <stfrench@microsoft.com>2018-06-15 20:17:40 -0400
commit35e2cc1ba755cf9dbd042e308b2928c868767a98 (patch)
tree7a4480897728404002b2a388f6f4245c902e90b4
parentd819d298c7258849d56eb400be436aff3ba2aae2 (diff)
cifs: Use correct packet length in SMB2_TRANSFORM header
In smb3_init_transform_rq(), 'orig_len' was only counting the request length, but forgot to count any data pages in the request. Writing or creating files with the 'seal' mount option was broken. In addition, do some code refactoring by exporting smb2_rqst_len() to calculate the appropriate packet size and avoid duplicating the same calculation all over the code. The start of the io vector is either the rfc1002 length (4 bytes) or a SMB2 header which is always > 4. Use this fact to check and skip the rfc1002 length if requested. Signed-off-by: Paulo Alcantara <palcantara@suse.de> Reviewed-by: Aurelien Aptel <aaptel@suse.com> Signed-off-by: Steve French <stfrench@microsoft.com>
-rw-r--r--fs/cifs/smb2ops.c7
-rw-r--r--fs/cifs/smb2proto.h2
-rw-r--r--fs/cifs/smbdirect.c19
-rw-r--r--fs/cifs/transport.c19
4 files changed, 24 insertions, 23 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index badcfb2f3c22..0356b5559c71 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -2485,7 +2485,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
2485 struct page **pages; 2485 struct page **pages;
2486 struct smb2_transform_hdr *tr_hdr; 2486 struct smb2_transform_hdr *tr_hdr;
2487 unsigned int npages = old_rq->rq_npages; 2487 unsigned int npages = old_rq->rq_npages;
2488 unsigned int orig_len = 0; 2488 unsigned int orig_len;
2489 int i; 2489 int i;
2490 int rc = -ENOMEM; 2490 int rc = -ENOMEM;
2491 2491
@@ -2499,9 +2499,6 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
2499 new_rq->rq_pagesz = old_rq->rq_pagesz; 2499 new_rq->rq_pagesz = old_rq->rq_pagesz;
2500 new_rq->rq_tailsz = old_rq->rq_tailsz; 2500 new_rq->rq_tailsz = old_rq->rq_tailsz;
2501 2501
2502 for (i = 0; i < old_rq->rq_nvec; i++)
2503 orig_len += old_rq->rq_iov[i].iov_len;
2504
2505 for (i = 0; i < npages; i++) { 2502 for (i = 0; i < npages; i++) {
2506 pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); 2503 pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
2507 if (!pages[i]) 2504 if (!pages[i])
@@ -2524,6 +2521,8 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
2524 if (!tr_hdr) 2521 if (!tr_hdr)
2525 goto err_free_iov; 2522 goto err_free_iov;
2526 2523
2524 orig_len = smb2_rqst_len(old_rq, false);
2525
2527 /* fill the 2nd iov with a transform header */ 2526 /* fill the 2nd iov with a transform header */
2528 fill_transform_hdr(tr_hdr, orig_len, old_rq); 2527 fill_transform_hdr(tr_hdr, orig_len, old_rq);
2529 new_rq->rq_iov[0].iov_base = tr_hdr; 2528 new_rq->rq_iov[0].iov_base = tr_hdr;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 78371c1a6503..3ae208ac2a77 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -113,6 +113,8 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile,
113extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); 113extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
114extern void smb2_reconnect_server(struct work_struct *work); 114extern void smb2_reconnect_server(struct work_struct *work);
115extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server); 115extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
116extern unsigned long
117smb2_rqst_len(struct smb_rqst *rqst, bool skip_rfc1002_marker);
116 118
117/* 119/*
118 * SMB2 Worker functions - most of protocol specific implementation details 120 * SMB2 Worker functions - most of protocol specific implementation details
diff --git a/fs/cifs/smbdirect.c b/fs/cifs/smbdirect.c
index e459c97151b3..6fd94d9ffac2 100644
--- a/fs/cifs/smbdirect.c
+++ b/fs/cifs/smbdirect.c
@@ -18,6 +18,7 @@
18#include "smbdirect.h" 18#include "smbdirect.h"
19#include "cifs_debug.h" 19#include "cifs_debug.h"
20#include "cifsproto.h" 20#include "cifsproto.h"
21#include "smb2proto.h"
21 22
22static struct smbd_response *get_empty_queue_buffer( 23static struct smbd_response *get_empty_queue_buffer(
23 struct smbd_connection *info); 24 struct smbd_connection *info);
@@ -2087,7 +2088,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
2087 struct kvec vec; 2088 struct kvec vec;
2088 int nvecs; 2089 int nvecs;
2089 int size; 2090 int size;
2090 unsigned int buflen = 0, remaining_data_length; 2091 unsigned int buflen, remaining_data_length;
2091 int start, i, j; 2092 int start, i, j;
2092 int max_iov_size = 2093 int max_iov_size =
2093 info->max_send_size - sizeof(struct smbd_data_transfer); 2094 info->max_send_size - sizeof(struct smbd_data_transfer);
@@ -2111,25 +2112,13 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
2111 log_write(ERR, "expected the pdu length in 1st iov, but got %zu\n", rqst->rq_iov[0].iov_len); 2112 log_write(ERR, "expected the pdu length in 1st iov, but got %zu\n", rqst->rq_iov[0].iov_len);
2112 return -EINVAL; 2113 return -EINVAL;
2113 } 2114 }
2114 iov = &rqst->rq_iov[1];
2115
2116 /* total up iov array first */
2117 for (i = 0; i < rqst->rq_nvec-1; i++) {
2118 buflen += iov[i].iov_len;
2119 }
2120 2115
2121 /* 2116 /*
2122 * Add in the page array if there is one. The caller needs to set 2117 * Add in the page array if there is one. The caller needs to set
2123 * rq_tailsz to PAGE_SIZE when the buffer has multiple pages and 2118 * rq_tailsz to PAGE_SIZE when the buffer has multiple pages and
2124 * ends at page boundary 2119 * ends at page boundary
2125 */ 2120 */
2126 if (rqst->rq_npages) { 2121 buflen = smb2_rqst_len(rqst, true);
2127 if (rqst->rq_npages == 1)
2128 buflen += rqst->rq_tailsz;
2129 else
2130 buflen += rqst->rq_pagesz * (rqst->rq_npages - 1) -
2131 rqst->rq_offset + rqst->rq_tailsz;
2132 }
2133 2122
2134 if (buflen + sizeof(struct smbd_data_transfer) > 2123 if (buflen + sizeof(struct smbd_data_transfer) >
2135 info->max_fragmented_send_size) { 2124 info->max_fragmented_send_size) {
@@ -2139,6 +2128,8 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
2139 goto done; 2128 goto done;
2140 } 2129 }
2141 2130
2131 iov = &rqst->rq_iov[1];
2132
2142 cifs_dbg(FYI, "Sending smb (RDMA): smb_len=%u\n", buflen); 2133 cifs_dbg(FYI, "Sending smb (RDMA): smb_len=%u\n", buflen);
2143 for (i = 0; i < rqst->rq_nvec-1; i++) 2134 for (i = 0; i < rqst->rq_nvec-1; i++)
2144 dump_smb(iov[i].iov_base, iov[i].iov_len); 2135 dump_smb(iov[i].iov_base, iov[i].iov_len);
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index a3ea42a4cb98..fb57dfbfb749 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -201,15 +201,24 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
201 return 0; 201 return 0;
202} 202}
203 203
204static unsigned long 204unsigned long
205smb2_rqst_len(struct smb_rqst *rqst) 205smb2_rqst_len(struct smb_rqst *rqst, bool skip_rfc1002_marker)
206{ 206{
207 unsigned int i; 207 unsigned int i;
208 struct kvec *iov = rqst->rq_iov; 208 struct kvec *iov;
209 int nvec;
209 unsigned long buflen = 0; 210 unsigned long buflen = 0;
210 211
212 if (skip_rfc1002_marker && rqst->rq_iov[0].iov_len == 4) {
213 iov = &rqst->rq_iov[1];
214 nvec = rqst->rq_nvec - 1;
215 } else {
216 iov = rqst->rq_iov;
217 nvec = rqst->rq_nvec;
218 }
219
211 /* total up iov array first */ 220 /* total up iov array first */
212 for (i = 0; i < rqst->rq_nvec; i++) 221 for (i = 0; i < nvec; i++)
213 buflen += iov[i].iov_len; 222 buflen += iov[i].iov_len;
214 223
215 /* 224 /*
@@ -262,7 +271,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
262 (char *)&val, sizeof(val)); 271 (char *)&val, sizeof(val));
263 272
264 for (j = 0; j < num_rqst; j++) 273 for (j = 0; j < num_rqst; j++)
265 send_length += smb2_rqst_len(&rqst[j]); 274 send_length += smb2_rqst_len(&rqst[j], true);
266 rfc1002_marker = cpu_to_be32(send_length); 275 rfc1002_marker = cpu_to_be32(send_length);
267 276
268 /* Generate a rfc1002 marker for SMB2+ */ 277 /* Generate a rfc1002 marker for SMB2+ */