Remove rfc1002 headers from SMB2 responses
Subsystems (2)
cover Remove rfc1002 headers from SMB2 responses
Steve, all
Please review but do not merge.
This is based on current sfrench/for-next and is the final step before we can start doing compounding.
The patch will break the soon to be merged SMBD support from Long Li so do not merge this. I suggest we wait until Long's patches are merged and I will rebase, and fixup the SMBD parts that this breaks.
The first patch removes the rfc1002 length field from all SMB2 responses. Unfortunately it is not easy to do this in a set of incremental patches as opposed to one single big patch since in the demultiplex loop we can not really distinguish between different response structures until we have read the full SMB2 header, and in order to read the header we must know whether there should be a rfc1002 length there or not. I.e. chicken and egg.
During developmnet of these patches I did have a series that performed the change one structure at a time but it is very ugly, doing memcpy to strip off the header when there should be none
and converting several helper functions to check their char*buf arguments whether it looked like the buffer started with a rfc1002 header or not. Very ugly and not I think something we want in the upstream commit history but if someone really wants to see the "individual change for each response structure" I could make those intermediate patchsets available.
It works for basic and manual testing. What remains is to ensure that SMBD is updated to not have to prepend the length field any more once those patches go in, and also SMB3 encryption.
I have not had a chance to test it so if someone could help here would be awesome.
The second patch updates the demultiplex loop so that it can handle compounded responses.
A message that is not in the archive (sent off-list or not yet received): 20180102223524.8389-1-lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org
PATCH 1/2 cifs: remove rfc1002 header from all SMB2 response structures
Separate out all the 4 byte rfc1002 headers so that they are no longer part of the SMB2 header structures to prepare for future work to add compounding support.
When using compounding, the wire format will consist of a single rfc1002 length header followed by one, or more, SMB2 headers, like this :
* 4 byte rfc1002 length
* SMB2 header
* SMB2 header
* ...
--- fs/cifs/cifsglob.h | 2 + fs/cifs/cifssmb.c | 9 ++- fs/cifs/connect.c | 28 ++++++--- fs/cifs/misc.c | 2 +- fs/cifs/smb1ops.c | 1 + fs/cifs/smb2glob.h | 5 -- fs/cifs/smb2maperror.c | 8 ++- fs/cifs/smb2misc.c | 110 +++++++++++++++++---------------- fs/cifs/smb2ops.c | 159 ++++++++++++++++++++++++++++++------------------ fs/cifs/smb2pdu.c | 105 +++++++++++++++----------------- fs/cifs/smb2pdu.h | 65 ++++++-------------- fs/cifs/smb2proto.h | 5 +- fs/cifs/smb2transport.c | 6 +- fs/cifs/transport.c | 4 +- 14 files changed, 268 insertions(+), 241 deletions(-)
fs/cifs/cifsglob.h +2 -0
@@ -460,6 +460,7 @@ struct smb_version_values {__u32 exclusive_lock_type;__u32 shared_lock_type;__u32 unlock_lock_type; +size_t header_preamble_size;size_t header_size;size_t max_header_size;size_t read_rsp_size;
@@ -656,6 +657,7 @@ struct TCP_Server_Info {struct delayed_work echo;/* echo ping workqueue job */ char *smallbuf;/* pointer to current "small" buffer */ char *bigbuf;/* pointer to current "big" buffer */ +unsigned int total_size;/* Total size of this PDU */ unsigned int total_read;/* total amount of data read in this pass */ #ifdef CONFIG_CIFS_FSCACHE struct fscache_cookie *fscache;/* client index cache cookie */
fs/cifs/cifssmb.c +6 -3
@@ -1453,7 +1453,9 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)unsigned int data_offset, data_len;struct cifs_readdata *rdata = mid->callback_data;char *buf = server->smallbuf; -unsigned int buflen =get_rfc1002_length (buf) +4 ; +unsigned int buflen; + + buflen = server->total_size + server->vals->header_preamble_size;cifs_dbg (FYI ,"%s: mid=%llu offset=%llu bytes=%u\n" , __func__, mid->mid, rdata->offset, rdata->bytes);
@@ -1464,7 +1466,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)* the Mid. */ len = min_t(unsigned int, buflen, server->vals->read_rsp_size) - -HEADER_SIZE (server) +1 ; +HEADER_SIZE (server) +1 ; length =cifs_read_from_socket (server, buf +HEADER_SIZE (server) -1 , len);
@@ -1502,7 +1504,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)return cifs_readv_discard (server, mid); } - data_offset = server->ops->read_data_offset (buf) +4 ; + data_offset = server->ops->read_data_offset (buf) + + server->vals->header_preamble_size;if (data_offset < server->total_read) {/* * win2k8 sometimes sends an offset of 0 when the read
fs/cifs/connect.c +20 -8
@@ -763,10 +763,11 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) {int length;char *buf = server->smallbuf; -unsigned int pdu_length =get_rfc1002_length (buf); +unsigned int pdu_length = server->total_size;/* make sure this will fit in a large buffer */ -if (pdu_length > CIFSMaxBufSize +MAX_HEADER_SIZE (server) -4 ) { +if (pdu_length > CIFSMaxBufSize +MAX_HEADER_SIZE (server) - + server->vals->header_preamble_size) {cifs_dbg (VFS ,"SMB response too long (%u bytes)\n" , pdu_length);cifs_reconnect (server);wake_up (&server->response_q);
@@ -781,8 +782,11 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) }/* now read the rest */ - length =cifs_read_from_socket (server, buf +HEADER_SIZE (server) -1 , - pdu_length -HEADER_SIZE (server) +1 +4 ); + length =cifs_read_from_socket (server, + buf +HEADER_SIZE (server) -1 , + pdu_length -HEADER_SIZE (server) +1 + + server->vals->header_preamble_size); +if (length <0 )return length; server->total_read += length;
@@ -862,20 +866,26 @@ cifs_demultiplex_thread(void *p) length =cifs_read_from_socket (server, buf, pdu_length);if (length <0 )continue ; - server->total_read = length; + +if (server->vals->header_preamble_size ==0 ) + server->total_read =0 ; +else + server->total_read = length;/* * The right amount was read from socket - 4 bytes, * so we can now interpret the length field. */ pdu_length =get_rfc1002_length (buf); + server->total_size = pdu_length;cifs_dbg (FYI ,"RFC1002 header 0x%x\n" , pdu_length);if (!is_smb_response (server, buf[0 ]))continue ;/* make sure we have enough to get to the MID */ -if (pdu_length <HEADER_SIZE (server) -1 -4 ) { +if (pdu_length <HEADER_SIZE (server) -1 - + server->vals->header_preamble_size) {cifs_dbg (VFS ,"SMB response too short (%u bytes)\n" , pdu_length);cifs_reconnect (server);
@@ -884,8 +894,10 @@ cifs_demultiplex_thread(void *p) }/* read down to the MID */ - length =cifs_read_from_socket (server, buf +4 , -HEADER_SIZE (server) -1 -4 ); + length =cifs_read_from_socket (server, + buf + server->vals->header_preamble_size, +HEADER_SIZE (server) -1 + - server->vals->header_preamble_size);if (length <0 )continue ; server->total_read += length;
fs/cifs/misc.c +1 -1
@@ -151,7 +151,7 @@ cifs_buf_get(void)* SMB2 header is bigger than CIFS one - no problems to clean some * more bytes for CIFS. */ -size_t buf_size =sizeof (struct smb2_hdr ); +size_t buf_size =sizeof (struct smb2_sync_hdr );/* * We could use negotiated size instead of max_msgsize -
fs/cifs/smb1ops.c +1 -0
@@ -1120,6 +1120,7 @@ struct smb_version_values smb1_values = { .exclusive_lock_type = 0, .shared_lock_type = LOCKING_ANDX_SHARED_LOCK, .unlock_lock_type = 0, + .header_preamble_size = 4, .header_size = sizeof(struct smb_hdr), .max_header_size = MAX_CIFS_HDR_SIZE, .read_rsp_size = sizeof(READ_RSP),
fs/cifs/smb2glob.h +0 -5
@@ -61,9 +61,4 @@/* Maximum buffer size value we can send with 1 credit */ #define SMB2_MAX_BUFFER_SIZE 65536 -static inline struct smb2_sync_hdr *get_sync_hdr (void *buf) -{ -return &(((struct smb2_hdr *)buf)->sync_hdr); -} -#endif /* _SMB2_GLOB_H */
fs/cifs/smb2maperror.c +6 -2
@@ -2450,10 +2450,14 @@ smb2_print_status(__le32 status)int map_smb2_to_linux_error (char *buf,bool log_err) { -struct smb2_sync_hdr *shdr =get_sync_hdr (buf); +struct smb2_sync_hdr *shdr;unsigned int i;int rc = -EIO ; -__le32 smb2err = shdr->Status; +__le32 smb2err; + + shdr = (struct smb2_sync_hdr *)buf; + + smb2err = shdr->Status;if (smb2err ==0 )return 0 ;
fs/cifs/smb2misc.c +56 -54
241 lines not on this page · raw message
fs/cifs/smb2ops.c +99 -60
412 lines not on this page · raw message
fs/cifs/smb2pdu.c +49 -56
296 lines not on this page · raw message
fs/cifs/smb2pdu.h +19 -46
189 lines not on this page · raw message
fs/cifs/smb2proto.h +3 -2
@@ -37,7 +37,8 @@ extern int map_smb2_to_linux_error(char *buf, bool log_err);extern int smb2_check_message (char *buf,unsigned int length,struct TCP_Server_Info *server);extern unsigned int smb2_calc_size (void *buf); -extern char *smb2_get_data_area_len (int *off,int *len,struct smb2_hdr *hdr); +extern char *smb2_get_data_area_len (int *off,int *len, +struct smb2_sync_hdr *shdr);extern __le16 *cifs_convert_path_to_utf16 (const char *from,struct cifs_sb_info *cifs_sb);
@@ -122,7 +123,7 @@ extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);extern int SMB2_open (const unsigned int xid,struct cifs_open_parms *oparms,__le16 *path,__u8 *oplock,struct smb2_file_all_info *buf, -struct smb2_err_rsp **err_buf); +struct kvec *err_iov); extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, u32 opcode, bool is_fsctl, bool use_ipc,
fs/cifs/smb2transport.c +3 -3
@@ -624,10 +624,10 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,struct smb_rqst rqst = { .rq_iov = iov, .rq_nvec =2 }; - iov[0 ].iov_base = (char *)mid->resp_buf; + iov[0 ].iov_base =NULL ; iov[0 ].iov_len =4 ; - iov[1 ].iov_base = (char *)mid->resp_buf +4 ; - iov[1 ].iov_len = len; + iov[1 ].iov_base = (char *)mid->resp_buf; + iov[1 ].iov_len = server->total_size;dump_smb (mid->resp_buf,min_t (u32,80 , len));/* convert the length into a more usable form */
fs/cifs/transport.c +3 -1
@@ -779,7 +779,9 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, buf = (char *)midQ->resp_buf; resp_iov->iov_base = buf; - resp_iov->iov_len =get_rfc1002_length (buf) +4 ; + resp_iov->iov_len = ses->server->total_size + + ses->server->vals->header_preamble_size; +if (midQ->large_buf) *resp_buf_type =CIFS_LARGE_BUFFER ;else
Signature · 1 line
2.13.3
A message that is not in the archive (sent off-list or not yet received): 20180102223524.8389-2-lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org
RE: [PATCH 1/2] cifs: remove rfc1002 header from all SMB2 response structures
Quoted 13 lines
-----Original Message-----
From: [email protected] [mailto:linux-cifs- [email protected]] On Behalf Of Ronnie Sahlberg
Sent: Tuesday, January 2, 2018 5:35 PM
To: linux-cifs <[email protected]>
Cc: Steve French <[email protected]>
Subject: [PATCH 1/2] cifs: remove rfc1002 header from all SMB2 response structuresSeparate out all the 4 byte rfc1002 headers so that they are no longer part of the SMB2 header structures to prepare for future work to add compounding support.
Quoted 7 lines
When using compounding, the wire format will consist of a single rfc1002 length header followed by one, or more, SMB2 headers, like this :
* 4 byte rfc1002 length
* SMB2 header
* SMB2 header
* ...
Comment purely on the changelog.
This second paragraph is somewhat misleading, and should perhaps be omitted. The RFC1002 length is a transport frame marker, and used only on stream-based transports such as TCP. For example, it's not present when the transport is SMB Direct. There is no protocol dependency on its use by Compounding.
Tom.
RE: [PATCH 1/2] cifs: remove rfc1002 header from all SMB2 response structures
In reply to a message not in the archiveQuoted 129 lines
Subject: [PATCH 1/2] cifs: remove rfc1002 header from all SMB2 response structures
Separate out all the 4 byte rfc1002 headers so that they are no longer part of the SMB2 header structures to prepare for future work to add compounding support.
When using compounding, the wire format will consist of a single rfc1002 length header followed by one, or more, SMB2 headers, like this :
* 4 byte rfc1002 length
* SMB2 header
* SMB2 header
* ...Signed-off-by Ronnie Sahlberg <[email protected]>--- fs/cifs/cifsglob.h | 2 + fs/cifs/cifssmb.c | 9 ++- fs/cifs/connect.c | 28 ++++++--- fs/cifs/misc.c | 2 +- fs/cifs/smb1ops.c | 1 + fs/cifs/smb2glob.h | 5 -- fs/cifs/smb2maperror.c | 8 ++- fs/cifs/smb2misc.c | 110 +++++++++++++++++---------------- fs/cifs/smb2ops.c | 159 ++++++++++++++++++++++++++++++------------ ------ fs/cifs/smb2pdu.c | 105 +++++++++++++++----------------- fs/cifs/smb2pdu.h | 65 ++++++-------------- fs/cifs/smb2proto.h | 5 +- fs/cifs/smb2transport.c | 6 +- fs/cifs/transport.c | 4 +- 14 files changed, 268 insertions(+), 241 deletions(-)fs/cifs/cifsglob.h +2
-0@@ -460,6 +460,7 @@ struct smb_version_values {__u32 exclusive_lock_type;__u32 shared_lock_type;__u32 unlock_lock_type; +size_t header_preamble_size;size_t header_size;size_t max_header_size;size_t read_rsp_size;@@ -656,6 +657,7 @@ struct TCP_Server_Info {struct delayed_work echo;/* echo ping workqueue job */ char *smallbuf;/* pointer to current "small" buffer */ char *bigbuf;/* pointer to current "big" buffer */ +unsigned int total_size;/* Total size of this PDU */ unsigned int total_read;/* total amount of data read in this pass */ #ifdef CONFIG_CIFS_FSCACHE struct fscache_cookie *fscache;/* client index cache cookie */ fs/cifs/cifssmb.c +3
-1@@ -1453,7 +1453,9 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)unsigned int data_offset, data_len;struct cifs_readdata *rdata = mid->callback_data;char *buf = server->smallbuf; -unsigned int buflen =get_rfc1002_length (buf) +4 ; +unsigned int buflen; + + buflen = server->total_size + server->vals->header_preamble_size; cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",fs/cifs/cifssmb.c +4
-2__func__, mid->mid, rdata->offset, rdata->bytes);@@ -1464,7 +1466,7 @@ cifs_readv_receive(struct TCP_Server_Info*server, struct mid_q_entry *mid) * the Mid. */ len = min_t(unsigned int, buflen, server->vals->read_rsp_size) - -HEADER_SIZE (server) +1 ; +HEADER_SIZE (server) +1 ; length =cifs_read_from_socket (server, buf +HEADER_SIZE (server) -1 , len);@@ -1502,7 +1504,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)return cifs_readv_discard (server, mid); } - data_offset = server->ops->read_data_offset (buf) +4 ; + data_offset = server->ops->read_data_offset (buf) + + server->vals->header_preamble_size;if (data_offset < server->total_read) {/* fs/cifs/cifssmb.c +0
-0* win2k8 sometimes sends an offset of 0 when the read fs/cifs/connect.c +3
-2@@ -763,10 +763,11 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) {int length;char *buf = server->smallbuf; -unsigned int pdu_length =get_rfc1002_length (buf); +unsigned int pdu_length = server->total_size;/* make sure this will fit in a large buffer */ -if (pdu_length > CIFSMaxBufSize +MAX_HEADER_SIZE (server) -4 ) { +if (pdu_length > CIFSMaxBufSize +MAX_HEADER_SIZE (server) - + server->vals->header_preamble_size) {cifs_dbg (VFS ,"SMB response too long (%u bytes)\n" , pdu_length);fs/cifs/connect.c +5
-2cifs_reconnect (server);wake_up (&server->response_q);@@ -781,8 +782,11 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) }/* now read the rest */ - length =cifs_read_from_socket (server, buf +HEADER_SIZE (server) -1 , - pdu_length -HEADER_SIZE (server) +1 +4 ); + length =cifs_read_from_socket (server, + buf +HEADER_SIZE (server) -1 , + pdu_length -HEADER_SIZE (server) +1 + + server->vals->header_preamble_size); +if (length <0 )fs/cifs/connect.c +0
-0return length; server->total_read += length;
fs/cifs/connect.c cifs_demultiplex_thread(void *p) · line 865
Quoted 4 lines
fs/cifs/connect.c +0
-1@@ -862,20 +866,26 @@ cifs_demultiplex_thread(void *p) length =cifs_read_from_socket (server, buf, pdu_length);if (length <0 )continue ; - server->total_read = length;
With this patch, most of the SMB upper layer code will no longer call get_rfc1002_length().
This is slightly out of topic. Maybe we should also look at implementing a transport layer to further abstract the transport details.
E.g. the call to cifs_read_from_socket() above is for reading the payload size (with one or more SMB2 PDUs). How about renaming it to cifs_read_payload_size(), and then depending on what transport is, do the following:
TCP: read from socket and return the payload size
RDMA: return the SMB Direct payload size
future transport: return the payload size
Adding a transport layer will hide those details, and make cifs_demultiplex_thread() cleaner. It also becomes easier to implement multiple channels and more transport support (e.g. HV Socket).
Quoted 1,560 lines
fs/cifs/connect.c +8
-1+ +if (server->vals->header_preamble_size ==0 ) + server->total_read =0 ; +else + server->total_read = length;/* * The right amount was read from socket - 4 bytes, * so we can now interpret the length field. */ pdu_length =get_rfc1002_length (buf); + server->total_size = pdu_length;cifs_dbg (FYI ,"RFC1002 header 0x%x\n" , pdu_length);if (!is_smb_response (server, buf[0 ]))continue ;/* make sure we have enough to get to the MID */ -if (pdu_length <HEADER_SIZE (server) -1 -4 ) { +if (pdu_length <HEADER_SIZE (server) -1 - + server->vals->header_preamble_size) { cifs_dbg(VFS, "SMB response too short (%u bytes)\n", pdu_length);fs/cifs/connect.c +4
-2cifs_reconnect (server);@@ -884,8 +894,10 @@ cifs_demultiplex_thread(void *p) }/* read down to the MID */ - length =cifs_read_from_socket (server, buf +4 , -HEADER_SIZE (server) -1 -4 ); + length =cifs_read_from_socket (server, + buf + server->vals->header_preamble_size, +HEADER_SIZE (server) -1 + - server->vals->header_preamble_size);if (length <0 )continue ; server->total_read += length;fs/cifs/misc.c +1
-1@@ -151,7 +151,7 @@ cifs_buf_get(void)* SMB2 header is bigger than CIFS one - no problems to clean some * more bytes for CIFS. */ -size_t buf_size =sizeof (struct smb2_hdr ); +size_t buf_size =sizeof (struct smb2_sync_hdr );/* * We could use negotiated size instead of max_msgsize - fs/cifs/smb1ops.c +1
-0@@ -1120,6 +1120,7 @@ struct smb_version_values smb1_values = { .exclusive_lock_type = 0, .shared_lock_type = LOCKING_ANDX_SHARED_LOCK, .unlock_lock_type = 0, + .header_preamble_size = 4, .header_size = sizeof(struct smb_hdr), .max_header_size = MAX_CIFS_HDR_SIZE, .read_rsp_size = sizeof(READ_RSP),fs/cifs/smb2glob.h +0
-5@@ -61,9 +61,4 @@/* Maximum buffer size value we can send with 1 credit */ #define SMB2_MAX_BUFFER_SIZE 65536 -static inline struct smb2_sync_hdr *get_sync_hdr (void *buf) -{ -return &(((struct smb2_hdr *)buf)->sync_hdr); -} -#endif /* _SMB2_GLOB_H */ fs/cifs/smb2maperror.c +6
-2@@ -2450,10 +2450,14 @@ smb2_print_status(__le32 status)int map_smb2_to_linux_error (char *buf,bool log_err) { -struct smb2_sync_hdr *shdr =get_sync_hdr (buf); +struct smb2_sync_hdr *shdr;unsigned int i;int rc = -EIO ; -__le32 smb2err = shdr->Status; +__le32 smb2err; + + shdr = (struct smb2_sync_hdr *)buf; + + smb2err = shdr->Status;if (smb2err ==0 )return 0 ;fs/cifs/smb2misc.c +8
-7@@ -96,17 +96,18 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {int smb2_check_message (char *buf,unsigned int length,struct TCP_Server_Info *srvr) { -struct smb2_pdu *pdu = (struct smb2_pdu *)buf; -struct smb2_hdr *hdr = &pdu->hdr; -struct smb2_sync_hdr *shdr =get_sync_hdr (buf); +struct smb2_sync_pdu *pdu; +struct smb2_sync_hdr *shdr;__u64 mid; -__u32 len =get_rfc1002_length (buf);__u32 clc_len;/* calculated length */ int command; +int pdu_size; +int hdr_size; -/* BB disable following printk later */ -cifs_dbg (FYI ,"%s length: 0x%x, smb_buf_length: 0x%x\n" , - __func__, length, len); + shdr = (struct smb2_sync_hdr *)buf; + pdu_size =sizeof (struct smb2_sync_pdu ); + hdr_size =sizeof (struct smb2_sync_hdr ); + pdu = (struct smb2_sync_pdu *)shdr;fs/cifs/smb2misc.c +2
-2/* * Add function to do table lookup of StructureSize by command @@ -136,8 +137,8 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) } mid =le64_to_cpu (shdr->MessageId); -if (length <sizeof (struct smb2_pdu )) { -if ((length >=sizeof (struct smb2_hdr )) +if (length < pdu_size) { +if ((length >= hdr_size) && (shdr->Status !=0 )) { pdu->StructureSize2 =0 ;fs/cifs/smb2misc.c +1
-1/* @@ -150,7 +151,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) }return 1 ; } -if (len > CIFSMaxBufSize +MAX_SMB2_HDR_SIZE -4 ) { +if (length > CIFSMaxBufSize +MAX_SMB2_HDR_SIZE ) { cifs_dbg(VFS, "SMB length greater than maximum, mid=%llu\n",fs/cifs/smb2misc.c +4
-10mid);return 1 ;@@ -189,26 +190,20 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) } } -if (4 + len != length) { - cifs_dbg(VFS, "Total length %u RFC1002 length %u mismatch mid %llu\n", - length, 4 + len, mid); -return 1 ; - } + clc_len = smb2_calc_size(buf); - clc_len =smb2_calc_size (hdr); - -if (4 + len != clc_len) { +if (length != clc_len) { cifs_dbg(FYI, "Calculated size %u length %u mismatch mid %llu\n", - clc_len, 4 + len, mid); + clc_len, length, mid);/* create failed on symlink */ if (command ==SMB2_CREATE_HE && shdr->Status ==STATUS_STOPPED_ON_SYMLINK )return 0 ;/* Windows 7 server returns 24 bytes more */ -if (clc_len +20 == len && command == SMB2_OPLOCK_BREAK_HE) +if (clc_len +24 == length && command ==SMB2_OPLOCK_BREAK_HE )return 0 ;fs/cifs/smb2misc.c +3
-3/* server can return one byte more due to implied bcc[0] */ -if (clc_len ==4 + len +1 ) +if (clc_len == length +1 )return 0 ;/* @@ -218,10 +213,10 @@ smb2_check_message(char *buf, unsigned intlength, struct TCP_Server_Info *srvr) * Log the server error (once), but allow it and continue * since the frame is parseable. */ -if (clc_len <4 /* RFC1001 header size */ + len) { +if (clc_len < length) {printk_once (KERN_WARNING "SMB2 server sent bad RFC1001 len %d not %d\n", - len, clc_len - 4); + length, clc_len);return 0 ;fs/cifs/smb2misc.c +1
-2}@@ -262,15 +257,14 @@ static const boolhas_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = { * area and the offset to it (from the beginning of the smb are also returned. */ char * -smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) +smb2_get_data_area_len(int *off, int *len, struct smb2_sync_hdr *shdr) { - struct smb2_sync_hdr *shdr = get_sync_hdr(hdr); *off = 0; *len = 0; /* error responses do not have data area */ if (shdr->Status && shdr->Status !=
STATUS_MORE_PROCESSING_REQUIRED&&fs/cifs/smb2misc.c +1
-1- (((struct smb2_err_rsp *)hdr)->StructureSize) == + (((struct smb2_err_rsp *)shdr)->StructureSize) ==
SMB2_ERROR_STRUCTURE_SIZE2)fs/cifs/smb2misc.c +8
-10return NULL ;@@ -282,42 +276,44 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)switch (shdr->Command) {case SMB2_NEGOTIATE : *off =le16_to_cpu ( - ((struct smb2_negotiate_rsp *)hdr)- >SecurityBufferOffset); + ((struct smb2_negotiate_rsp *)shdr)- >SecurityBufferOffset); *len =le16_to_cpu ( - ((struct smb2_negotiate_rsp *)hdr)- >SecurityBufferLength); + ((struct smb2_negotiate_rsp *)shdr)- >SecurityBufferLength);break ;case SMB2_SESSION_SETUP : *off =le16_to_cpu ( - ((struct smb2_sess_setup_rsp *)hdr)- >SecurityBufferOffset); + ((struct smb2_sess_setup_rsp *)shdr)- >SecurityBufferOffset); *len =le16_to_cpu ( - ((struct smb2_sess_setup_rsp *)hdr)- >SecurityBufferLength); + ((struct smb2_sess_setup_rsp *)shdr)- >SecurityBufferLength);break ;case SMB2_CREATE : *off =le32_to_cpu ( - ((struct smb2_create_rsp *)hdr)->CreateContextsOffset); + ((struct smb2_create_rsp *)shdr)->CreateContextsOffset); *len =le32_to_cpu ( - ((struct smb2_create_rsp *)hdr)->CreateContextsLength); + ((struct smb2_create_rsp *)shdr)- >CreateContextsLength);break ;case SMB2_QUERY_INFO : *off =le16_to_cpu ( - ((struct smb2_query_info_rsp *)hdr)- >OutputBufferOffset); + ((struct smb2_query_info_rsp *)shdr)- >OutputBufferOffset); *len =le32_to_cpu ( - ((struct smb2_query_info_rsp *)hdr)- >OutputBufferLength); + ((struct smb2_query_info_rsp *)shdr)- >OutputBufferLength);break ;case SMB2_READ : - *off = ((struct smb2_read_rsp *)hdr)->DataOffset; - *len = le32_to_cpu(((struct smb2_read_rsp *)hdr)-Quoted 1 line
DataLength);
fs/cifs/smb2misc.c +3
-0+/* TODO: is this a bug ? */ + *off = ((struct smb2_read_rsp *)shdr)->DataOffset; + *len = le32_to_cpu(((struct smb2_read_rsp *)shdr)-Quoted 1 line
DataLength);
fs/cifs/smb2misc.c +0
-1break ;case SMB2_QUERY_DIRECTORY : *off = le16_to_cpu( - ((struct smb2_query_directory_rsp *)hdr)-Quoted 1 line
OutputBufferOffset);
fs/cifs/smb2misc.c +1
-0+ ((struct smb2_query_directory_rsp *)shdr)-Quoted 1 line
OutputBufferOffset);
fs/cifs/smb2misc.c +0
-1*len = le32_to_cpu( - ((struct smb2_query_directory_rsp *)hdr)-Quoted 1 line
OutputBufferLength);
fs/cifs/smb2misc.c +1
-0+ ((struct smb2_query_directory_rsp *)shdr)-Quoted 1 line
OutputBufferLength);
fs/cifs/smb2misc.c +0
-2break ;case SMB2_IOCTL : *off = le32_to_cpu( - ((struct smb2_ioctl_rsp *)hdr)->OutputOffset); - *len = le32_to_cpu(((struct smb2_ioctl_rsp *)hdr)-Quoted 1 line
OutputCount);
fs/cifs/smb2misc.c +10
-4+ ((struct smb2_ioctl_rsp *)shdr)->OutputOffset); + *len =le32_to_cpu ( + ((struct smb2_ioctl_rsp *)shdr)->OutputCount);break ;case SMB2_CHANGE_NOTIFY :default :@@ -362,13 +358,16 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)unsigned int smb2_calc_size (void *buf) { -struct smb2_pdu *pdu = (struct smb2_pdu *)buf; -struct smb2_hdr *hdr = &pdu->hdr; -struct smb2_sync_hdr *shdr =get_sync_hdr (hdr); +struct smb2_sync_pdu *pdu; +struct smb2_sync_hdr *shdr;int offset;/* the offset from the beginning of SMB to data area */ int data_length;/* the length of the variable length data area */ /* Structure Size has already been checked to make sure it is 64 */ -int len =4 +le16_to_cpu (shdr->StructureSize); +int len; + + pdu = (struct smb2_sync_pdu *)buf; + shdr = &pdu->sync_hdr; + len =le16_to_cpu (shdr->StructureSize);/* fs/cifs/smb2misc.c +1
-1* StructureSize2, ie length of fixed parameter area has already @@ -379,7 +378,7 @@ smb2_calc_size(void *buf)if (has_smb2_data_area[le16_to_cpu (shdr->Command)] == false) goto calc_size_exit; -smb2_get_data_area_len (&offset, &data_length, hdr); +smb2_get_data_area_len (&offset, &data_length, shdr);cifs_dbg (FYI ,"SMB2 data length %d offset %d\n" , data_length, offset);fs/cifs/smb2misc.c +4
-5if (data_length >0 ) {@@ -387,15 +386,14 @@ smb2_calc_size(void *buf)* Check to make sure that data area begins after fixed area, * Note that last byte of the fixed area is part of data area * for some commands, typically those with odd StructureSize, -* so we must add one to the calculation (and 4 to account for -* the size of the RFC1001 hdr. +* so we must add one to the calculation. */ -if (offset +4 +1 < len) { +if (offset +1 < len) { cifs_dbg(VFS, "data area offset %d overlaps SMB2 header %d\n", - offset + 4 + 1, len); + offset + 1, len); data_length =0 ; }else { - len =4 + offset + data_length; + len = offset + data_length; }fs/cifs/smb2misc.c +1
-1} calc_size_exit:@@ -578,7 +576,7 @@ smb2_is_valid_lease_break(char *buffer)bool smb2_is_valid_oplock_break (char *buffer,struct TCP_Server_Info *server) { -struct smb2_oplock_break_rsp *rsp = (struct smb2_oplock_break_rsp *)buffer; +struct smb2_oplock_break *rsp = (struct smb2_oplock_break *)buffer;struct list_head *tmp, *tmp1, *tmp2;fs/cifs/smb2misc.c +1
-1struct cifs_ses *ses;struct cifs_tcon *tcon;@@ -587,7 +585,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) cifs_dbg(FYI, "Checking for oplock break\n"); -if (rsp->hdr.sync_hdr.Command !=SMB2_OPLOCK_BREAK ) +if (rsp->sync_hdr.Command !=SMB2_OPLOCK_BREAK )return false;fs/cifs/smb2misc.c +6
-2if (rsp->StructureSize !=@@ -678,11 +676,15 @@ smb2_cancelled_close_fid(struct work_struct *work)int smb2_handle_cancelled_mid (char *buffer,struct TCP_Server_Info *server) { -struct smb2_sync_hdr *sync_hdr =get_sync_hdr (buffer); -struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer; +struct smb2_sync_hdr *sync_hdr; +struct smb2_create_rsp *rsp;struct cifs_tcon *tcon;struct close_cancelled_open *cancelled; + sync_hdr = (struct smb2_sync_hdr *)buffer; + + rsp = (struct smb2_create_rsp *)sync_hdr; +if (sync_hdr->Command !=SMB2_CREATE || sync_hdr->Status !=STATUS_SUCCESS )fs/cifs/smb2misc.c +0
-0return 0 ;fs/cifs/smb2ops.c +8
-1@@ -122,7 +122,14 @@ smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)static unsigned int smb2_get_credits (struct mid_q_entry *mid) { -struct smb2_sync_hdr *shdr =get_sync_hdr (mid->resp_buf); +char *buf = mid->resp_buf; +struct smb2_sync_hdr *shdr; + +if ( *(__u32 *)buf ==SMB2_PROTO_NUMBER || + *(__u32 *)buf ==SMB2_TRANSFORM_PROTO_NUM ) + shdr = (struct smb2_sync_hdr *)buf; +else + shdr = (struct smb2_sync_hdr *)(buf +4 );return le16_to_cpu (shdr->CreditRequest);}
fs/cifs/smb2ops.c +9
-3@@ -189,8 +196,12 @@ static struct mid_q_entry * smb2_find_mid(struct TCP_Server_Info *server, char *buf) { struct mid_q_entry *mid; -struct smb2_sync_hdr *shdr =get_sync_hdr (buf); -__u64 wire_mid =le64_to_cpu (shdr->MessageId); +struct smb2_sync_hdr *shdr; +__u64 wire_mid; + + shdr = (struct smb2_sync_hdr *)buf; + + wire_mid =le64_to_cpu (shdr->MessageId);if (shdr->ProtocolId ==SMB2_TRANSFORM_PROTO_NUM ) {cifs_dbg (VFS ,"encrypted frame parsing not supported yet" );@@ -214,7 +225,9 @@ static void smb2_dump_detail(void *buf) {#ifdef CONFIG_CIFS_DEBUG2 -struct smb2_sync_hdr *shdr =get_sync_hdr (buf); +struct smb2_sync_hdr *shdr; + + shdr = (struct smb2_sync_hdr *)buf; cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n", shdr->Command, shdr->Status, shdr->Flags, shdr-Quoted 1 line
MessageId,
fs/cifs/smb2ops.c +3
-1@@ -1230,7 +1243,9 @@ smb2_close_dir(const unsigned int xid, structcifs_tcon *tcon, static bool smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length) { - struct smb2_sync_hdr *shdr = get_sync_hdr(buf); + struct smb2_sync_hdr *shdr; + + shdr = (struct smb2_sync_hdr *)buf;fs/cifs/smb2ops.c +3
-1if (shdr->Status !=STATUS_PENDING )return false;@@ -1248,7 +1263,9 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)static bool smb2_is_session_expired (char *buf) { -struct smb2_sync_hdr *shdr =get_sync_hdr (buf); +struct smb2_sync_hdr *shdr; + + shdr = (struct smb2_sync_hdr *)buf;if (shdr->Status !=STATUS_NETWORK_SESSION_EXPIRED )fs/cifs/smb2ops.c +1
-0return false;@@ -1444,6 +1461,7 @@ smb2_query_symlink(const unsigned int xid, structcifs_tcon *tcon, __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;struct cifs_open_parms oparms;struct cifs_fid fid; +struct kvec err_iov = {NULL ,0 };struct smb2_err_rsp *err_buf =NULL ;struct smb2_symlink_err_rsp *symlink;fs/cifs/smb2ops.c +2
-1unsigned int sub_len;@@ -1464,15 +1482,16 @@ smb2_query_symlink(const unsigned int xid,struct cifs_tcon *tcon, oparms.fid = &fid; oparms.reconnect = false; - rc =SMB2_open (xid, &oparms, utf16_path, &oplock,NULL , &err_buf); + rc =SMB2_open (xid, &oparms, utf16_path, &oplock,NULL , &err_iov);if (!rc || !err_buf) {kfree (utf16_path);return -ENOENT ; } + err_buf = err_iov.iov_base; if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct
smb2_symlink_err_rsp) ||fs/cifs/smb2ops.c +3
-3- get_rfc1002_length(err_buf) + 4 < SMB2_SYMLINK_STRUCT_SIZE) { + err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE) {kfree (utf16_path);return -ENOENT ; }@@ -1485,13 +1504,13 @@ smb2_query_symlink(const unsigned int xid,struct cifs_tcon *tcon, print_len =le16_to_cpu (symlink->PrintNameLength); print_offset =le16_to_cpu (symlink->PrintNameOffset); -if (get_rfc1002_length (err_buf) +4 < +if (err_iov.iov_len <SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {kfree (utf16_path);return -ENOENT ; } -if (get_rfc1002_length (err_buf) +4 < +if (err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE + print_offset +
print_len) {fs/cifs/smb2ops.c +1
-1kfree (utf16_path);return -ENOENT ;@@ -2048,7 +2067,7 @@ static void fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq) { struct smb2_sync_hdr *shdr = - (struct smb2_sync_hdr *)old_rq- >rq_iov[1].iov_base; + (struct smb2_sync_hdr *)old_rq- >rq_iov[2].iov_base;unsigned int
orig_len= get_rfc1002_length(old_rq-Quoted 1 line
rq_iov[0].iov_base);
fs/cifs/smb2ops.c +1
-3memset (tr_hdr,0 ,sizeof (struct smb2_transform_hdr ));@@ -2057,15 +2076,13 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq) tr_hdr->Flags =cpu_to_le16 (0x01 );get_random_bytes (&tr_hdr->Nonce,SMB3_AES128CMM_NONCE );memcpy (&tr_hdr->SessionId, &shdr->SessionId,8 ); -inc_rfc1001_len (tr_hdr,sizeof (struct smb2_transform_hdr ) -4 ); -inc_rfc1001_len (tr_hdr, orig_len); }static struct scatterlist *init_sg (struct smb_rqst *rqst,u8 *sign) {unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages +1 ; -unsigned int assoc_data_len =sizeof (struct smb2_transform_hdr ) -24 ; +unsigned int assoc_data_len =sizeof (struct smb2_transform_hdr ) -20 ;fs/cifs/smb2ops.c +7
-8struct scatterlist *sg;unsigned int i;unsigned int j;@@ -2075,10 +2092,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign)return NULL ;sg_init_table (sg, sg_len); -sg_set_buf (&sg[0 ], rqst->rq_iov[0 ].iov_base +24 , assoc_data_len); +sg_set_buf (&sg[0 ], rqst->rq_iov[1 ].iov_base +20 , assoc_data_len);for (i =1 ; i < rqst->rq_nvec; i++) -sg_set_buf (&sg[i], rqst->rq_iov[i].iov_base, - rqst->rq_iov[i].iov_len); +sg_set_buf (&sg[i], rqst->rq_iov[i+1 ].iov_base, + rqst->rq_iov[i+1 ].iov_len);for (j =0 ; i < sg_len -1 ; i++, j++) {unsigned int len = (j < rqst->rq_npages -1 ) ? rqst->rq_pagesz : rqst->rq_tailsz;@@ -2110,17 +2127,18 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key) }/* * Encrypt or decrypt @rqst message. @rqst has the following format: -* iov[0] - transform header (associate data), -* iov[1-N] and pages - data to encrypt. -* On success return encrypted data in iov[1-N] and pages, leave iov[0] +* iov[0] - rfc1002 length +* iov[1] - transform header (associate data), +* iov[2-N] and pages - data to encrypt. +* On success return encrypted data in iov[2-N] and pages, leave iov[0-1] * untouched. */ static int crypt_message (struct TCP_Server_Info *server,struct smb_rqst *rqst,int enc) {struct smb2_transform_hdr *tr_hdr = - (struct smb2_transform_hdr *)rqst- >rq_iov[0].iov_base; - unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) -24;
fs/cifs/smb2ops.c +1
-0+ (struct smb2_transform_hdr *)rqst-Quoted 1 line
rq_iov[1].iov_base;
fs/cifs/smb2ops.c +1
-0+ unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) -20;
fs/cifs/smb2ops.c +3
-0int rc =0 ;struct scatterlist *sg;u8 sign[SMB2_SIGNATURE_SIZE ] = {};@@ -2207,6 +2225,9 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) return rc; } +/* This is called from smb_send_rqst. At this point we have the rfc1002 +* header as the first element in the vector. +*/ static int smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst
*new_rq,fs/cifs/smb2ops.c +14
-6struct smb_rqst *old_rq)@@ -2233,24 +2254,32 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, goto err_free_pages; } - iov =kmalloc_array (old_rq->rq_nvec,sizeof (struct kvec ), GFP_KERNEL); +/* Make space for one extra iov to hold the transform header */ + iov =kmalloc_array (old_rq->rq_nvec +1 ,sizeof (struct kvec ), +GFP_KERNEL );if (!iov) goto err_free_pages;/* copy all iovs from the old except the 1st one (rfc1002 length) */ -memcpy (&iov[1 ], &old_rq->rq_iov[1 ], +memcpy (&iov[2 ], &old_rq->rq_iov[1 ],sizeof (struct kvec ) * (old_rq->rq_nvec -1 )); +/* copy the rfc1002 iov */ +memcpy (iov[0 ].iov_base, old_rq->rq_iov[0 ].iov_base, + old_rq->rq_iov[0 ].iov_len); + new_rq->rq_iov = iov; - new_rq->rq_nvec = old_rq->rq_nvec; + new_rq->rq_nvec = old_rq->rq_nvec +1 ; tr_hdr =kmalloc (sizeof (struct smb2_transform_hdr ),GFP_KERNEL );if (!tr_hdr) goto err_free_iov; -/* fill the 1st iov with a transform header */ +/* fill the 2nd iov with a transform header */ fill_transform_hdr (tr_hdr, old_rq); - new_rq->rq_iov[0 ].iov_base = tr_hdr; - new_rq->rq_iov[0 ].iov_len =sizeof (struct smb2_transform_hdr ); +inc_rfc1001_len (new_rq->rq_iov[0 ].iov_base, +sizeof (struct smb2_transform_hdr )); + new_rq->rq_iov[1 ].iov_base = tr_hdr; + new_rq->rq_iov[1 ].iov_len =sizeof (struct smb2_transform_hdr );fs/cifs/smb2ops.c +8
-7/* copy pages form the old */ for (i =0 ; i < npages; i++) {@@ -2307,18 +2336,19 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf, unsigned int buf_data_size, struct page **pages, unsigned int npages, unsigned int page_data_size) { - struct kvec iov[2]; + struct kvec iov[3];struct smb_rqst rqst = {NULL }; -struct smb2_hdr *hdr;int rc; - iov[0 ].iov_base = buf; - iov[0 ].iov_len =sizeof (struct smb2_transform_hdr ); - iov[1 ].iov_base = buf +sizeof (struct smb2_transform_hdr ); - iov[1 ].iov_len = buf_data_size; + iov[0 ].iov_base =NULL ; + iov[0 ].iov_len =0 ; + iov[1 ].iov_base = buf; + iov[1 ].iov_len =sizeof (struct smb2_transform_hdr ); + iov[2 ].iov_base = buf +sizeof (struct smb2_transform_hdr ); + iov[2 ].iov_len = buf_data_size; rqst.rq_iov = iov; - rqst.rq_nvec =2 ; + rqst.rq_nvec =3 ; rqst.rq_pages = pages; rqst.rq_npages = npages;fs/cifs/smb2ops.c +4
-4rqst.rq_pagesz =PAGE_SIZE ;@@ -2330,10 +2360,10 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf, if (rc)return rc; -memmove (buf +4 , iov[1 ].iov_base, buf_data_size); - hdr = (struct smb2_hdr *)buf; - hdr->smb2_buf_length =cpu_to_be32 (buf_data_size + page_data_size); - server->total_read = buf_data_size + page_data_size +4 ; + +memmove (buf, iov[0 ].iov_base, buf_data_size); + + server->total_read = buf_data_size + page_data_size;fs/cifs/smb2ops.c +3
-1return rc; }@@ -2406,12 +2436,14 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, unsigned int cur_page_idx;unsigned int pad_len;struct cifs_readdata *rdata = mid->callback_data; -struct smb2_sync_hdr *shdr =get_sync_hdr (buf); +struct smb2_sync_hdr *shdr;struct bio_vec *bvec =NULL ;struct iov_iter iter;struct kvec iov;int length; + shdr = (struct smb2_sync_hdr *)buf; +if (shdr->Command !=SMB2_READ ) {cifs_dbg (VFS ,"only big read responses are supported\n" );fs/cifs/smb2ops.c +2
-2return -ENOTSUPP ;@@ -2529,11 +2561,11 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)unsigned int npages;struct page **pages;unsigned int len; -unsigned int buflen =get_rfc1002_length (buf) +4 ; +unsigned int buflen = server->total_read;int rc;int i =0 ; - len = min_t(unsigned int, buflen, server->vals->read_rsp_size - 4 + + len = min_t(unsigned int, buflen, server->vals->read_rsp_size +sizeof (struct smb2_transform_hdr )) -HEADER_SIZE (server) +1 ;rc = cifs_read_from_socket(server, buf +
HEADER_SIZE(server)- 1,
len);fs/cifs/smb2ops.c +2
-2@@ -2541,7 +2573,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)return rc; server->total_read += rc; - len =le32_to_cpu (tr_hdr->OriginalMessageSize) +4 - + len =le32_to_cpu (tr_hdr->OriginalMessageSize) - server->vals->read_rsp_size; npages =DIV_ROUND_UP (len,PAGE_SIZE );@@ -2568,7 +2600,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)if (rc) goto free_pages; - rc =decrypt_raw_data (server, buf, server->vals->read_rsp_size -4 , + rc =decrypt_raw_data (server, buf, server->vals->read_rsp_size, pages, npages, len);if (rc)fs/cifs/smb2ops.c +2
-2goto free_pages;@@ -2600,12 +2632,12 @@ receive_encrypted_standard(structTCP_Server_Info *server, { int length;char *buf = server->smallbuf; -unsigned int pdu_length =get_rfc1002_length (buf); +unsigned int pdu_length = server->total_read;unsigned int buf_size;struct mid_q_entry *mid_entry;/* switch to large buffer if too big for a small one */ -if (pdu_length +4 >MAX_CIFS_SMALL_BUFFER_SIZE ) { +if (pdu_length >MAX_CIFS_SMALL_BUFFER_SIZE ) { server->large_buf = true;memcpy (server->bigbuf, buf, server->total_read);fs/cifs/smb2ops.c +2
-2buf = server->bigbuf;@@ -2613,12 +2645,12 @@ receive_encrypted_standard(structTCP_Server_Info *server,/* now read the rest */ length =cifs_read_from_socket (server, buf +HEADER_SIZE (server) -1 , - pdu_length -HEADER_SIZE (server) +1 +4 ); + pdu_length -HEADER_SIZE (server) +1 );if (length <0 )return length; server->total_read += length; - buf_size = pdu_length +4 -sizeof (struct smb2_transform_hdr ); + buf_size = pdu_length -sizeof (struct smb2_transform_hdr ); length =decrypt_raw_data (server, buf, buf_size,NULL ,0 ,0 );fs/cifs/smb2ops.c +3
-3if (length)return length;@@ -2643,12 +2675,12 @@ static int smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) { char *buf = server->smallbuf; -unsigned int pdu_length =get_rfc1002_length (buf); +unsigned int pdu_length = server->total_read;struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;unsigned int orig_len =le32_to_cpu (tr_hdr->OriginalMessageSize); -if (pdu_length +4 <sizeof (struct smb2_transform_hdr ) + -sizeof (struct smb2_sync_hdr)) { +if (pdu_length <sizeof (struct smb2_transform_hdr ) + +sizeof (struct smb2_sync_hdr )) {fs/cifs/smb2ops.c +2
-2cifs_dbg (VFS ,"Transform message is too small (%u)\n" , pdu_length);cifs_reconnect (server);@@ -2656,14 +2688,14 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) return -ECONNABORTED; } -if (pdu_length +4 < orig_len +sizeof (struct smb2_transform_hdr )) { +if (pdu_length < orig_len +sizeof (struct smb2_transform_hdr )) {cifs_dbg (VFS ,"Transform message is broken\n" );cifs_reconnect (server);wake_up (&server->response_q);return -ECONNABORTED ; } -if (pdu_length +4 > CIFSMaxBufSize +MAX_HEADER_SIZE (server)) +if (pdu_length > CIFSMaxBufSize +MAX_HEADER_SIZE (server))return receive_encrypted_read (server, mid);fs/cifs/smb2ops.c +14
-7return receive_encrypted_standard (server, mid);@@ -3078,7 +3110,8 @@ struct smb_version_values smb20_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), + .header_preamble_size = 0, + .header_size = sizeof(struct smb2_sync_hdr), .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK,@@ -3098,7 +3131,8 @@ struct smb_version_values smb21_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), + .header_preamble_size = 0, + .header_size = sizeof(struct smb2_sync_hdr), .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK,@@ -3118,7 +3152,8 @@ struct smb_version_values smb3any_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), + .header_preamble_size = 0, + .header_size = sizeof(struct smb2_sync_hdr), .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK,@@ -3138,7 +3173,8 @@ struct smb_version_values smbdefault_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), + .header_preamble_size = 0, + .header_size = sizeof(struct smb2_sync_hdr), .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK,@@ -3158,7 +3194,8 @@ struct smb_version_values smb30_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), + .header_preamble_size = 0, + .header_size = sizeof(struct smb2_sync_hdr), .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK,@@ -3178,7 +3215,8 @@ struct smb_version_values smb302_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), + .header_preamble_size = 0, + .header_size = sizeof(struct smb2_sync_hdr), .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK,@@ -3199,7 +3237,8 @@ struct smb_version_values smb311_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), + .header_preamble_size = 0, + .header_size = sizeof(struct smb2_sync_hdr), .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK,fs/cifs/smb2pdu.c +1
-1@@ -577,7 +577,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES; security_blob =smb2_get_data_area_len (&blob_offset, &blob_length, - &rsp->hdr); + (struct smb2_sync_hdr *)rsp);/* fs/cifs/smb2pdu.c +3
-3* See MS-SMB2 section 2.2.4: if no blob, client picks default which * for us will be @@ -921,7 +921,7 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data) goto out_put_spnego_key; rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0 ].iov_base; - ses->Suid = rsp->hdr.sync_hdr.SessionId; + ses->Suid = rsp->sync_hdr.SessionId; ses->session_flags =le16_to_cpu (rsp->SessionFlags);@@ -997,13 +997,13 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)/* If true, rc here is expected and not an error */ if (sess_data->buf0_type !=CIFS_NO_BUFFER && - rsp->hdr.sync_hdr.Status ==STATUS_MORE_PROCESSING_REQUIRED ) + rsp->sync_hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) rc =0 ;if (rc) goto out; - if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 != + if (offsetof(struct smb2_sess_setup_rsp, Buffer) !=fs/cifs/smb2pdu.c +1
-1le16_to_cpu(rsp->SecurityBufferOffset)) {cifs_dbg (VFS ,"Invalid security buffer offset %d\n" ,le16_to_cpu (rsp->SecurityBufferOffset));@@ -1018,7 +1018,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data) cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n"); - ses->Suid = rsp->hdr.sync_hdr.SessionId; + ses->Suid = rsp->sync_hdr.SessionId; ses->session_flags =le16_to_cpu (rsp->SessionFlags);out:
fs/cifs/smb2pdu.c +1
-1@@ -1076,7 +1076,7 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data) rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0 ].iov_base; - ses->Suid = rsp->hdr.sync_hdr.SessionId; + ses->Suid = rsp->sync_hdr.SessionId; ses->session_flags =le16_to_cpu (rsp->SessionFlags);fs/cifs/smb2pdu.c +2
-2rc =SMB2_sess_establish_session (sess_data);@@ -1298,7 +1298,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, }if (tcon ==NULL ) { - ses->ipc_tid = rsp->hdr.sync_hdr.TreeId; + ses->ipc_tid = rsp->sync_hdr.TreeId; goto tcon_exit; }@@ -1325,7 +1325,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, tcon->maximal_access =le32_to_cpu (rsp->MaximalAccess); tcon->tidStatus = CifsGood; tcon->need_reconnect = false; - tcon->tid = rsp->hdr.sync_hdr.TreeId; + tcon->tid = rsp->sync_hdr.TreeId;strlcpy (tcon->treeName, tree,sizeof (tcon->treeName));fs/cifs/smb2pdu.c +1
-1if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) &&@@ -1345,7 +1345,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, return rc; tcon_error_exit: -if (rsp && rsp->hdr.sync_hdr.Status == STATUS_BAD_NETWORK_NAME) { +if (rsp && rsp->sync_hdr.Status ==STATUS_BAD_NETWORK_NAME ) {fs/cifs/smb2pdu.c +1
-1cifs_dbg (VFS ,"BAD_NETWORK_NAME: %s\n" , tree); } goto tcon_exit;@@ -1451,7 +1451,7 @@ parse_lease_state(struct TCP_Server_Info *server,struct smb2_create_rsp *rsp, unsigned int remaining;char *name; - data_offset = (char *)rsp +4 +le32_to_cpu (rsp- >CreateContextsOffset); + data_offset = (char *)rsp +le32_to_cpu (rsp- >CreateContextsOffset);fs/cifs/smb2pdu.c +1
-1remaining =le32_to_cpu (rsp->CreateContextsLength); cc = (struct create_context *)data_offset;while (remaining >=sizeof (struct create_context )) {@@ -1679,7 +1679,7 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, __u8 *oplock, struct smb2_file_all_info *buf, - struct smb2_err_rsp **err_buf) + struct kvec *err_iov) {fs/cifs/smb2pdu.c +4
-3struct smb2_create_req *req;struct smb2_create_rsp *rsp;@@ -1815,9 +1815,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, if (rc != 0) {cifs_stats_fail_inc (tcon,SMB2_CREATE_HE ); -if (err_buf && rsp) - *err_buf =kmemdup (rsp,get_rfc1002_length (rsp) +4 , -GFP_KERNEL ); + if (err_iov && rsp) { + *err_iov = rsp_iov; + rsp =NULL ; + } goto creat_exit;fs/cifs/smb2pdu.c +0
-1}@@ -1856,7 +1857,6 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, {struct smb2_ioctl_req *req;struct smb2_ioctl_rsp *rsp; -struct smb2_sync_hdr *shdr;struct cifs_ses *ses;struct kvec iov[2 ];fs/cifs/smb2pdu.c +1
-1struct kvec rsp_iov;@@ -1987,7 +1987,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, goto ioctl_exit; } -if (get_rfc1002_length (rsp) <le32_to_cpu (rsp->OutputOffset) + *plen) { +if (rsp_iov.iov_len <le32_to_cpu (rsp->OutputOffset) + *plen) { cifs_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n",*plen,
fs/cifs/smb2pdu.c +1
-2le32_to_cpu(rsp->OutputOffset)); *plen =0 ;@@ -2001,8 +2001,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, goto ioctl_exit; } - shdr =get_sync_hdr (rsp); -memcpy (*out_data, (char *)shdr +le32_to_cpu (rsp->OutputOffset), *plen); +memcpy (*out_data, (char *)rsp +le32_to_cpu (rsp->OutputOffset), *plen);
ioctl_exit:fs/cifs/smb2pdu.c +11
-13free_rsp_buf (resp_buftype, rsp);return rc;@@ -2083,13 +2082,12 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, }static int -validate_buf (unsigned int offset,unsigned int buffer_length, -struct smb2_hdr *hdr,unsigned int min_buf_size) - +validate_iov (unsigned int offset,unsigned int buffer_length, +struct kvec *iov,unsigned int min_buf_size) { -unsigned int smb_len =be32_to_cpu (hdr->smb2_buf_length); -char *end_of_smb = smb_len +4 /* RFC1001 length field */ + (char *)hdr; -char *begin_of_buf =4 /* RFC1001 len field */ + offset + (char *)hdr; +unsigned int smb_len = iov->iov_len; +char *end_of_smb = smb_len + (char *)iov->iov_base; +char *begin_of_buf = offset + (char *)iov->iov_base;char *end_of_buf = begin_of_buf + buffer_length;@@ -2119,18 +2117,17 @@ validate_buf(unsigned int offset, unsigned intbuffer_length, * Caller must free buffer. */ static int -validate_and_copy_buf (unsigned int offset,unsigned int buffer_length, -struct smb2_hdr *hdr,unsigned int minbufsize, +validate_and_copy_iov (unsigned int offset,unsigned int buffer_length, +struct kvec *iov,unsigned int minbufsize,char *data) - { -char *begin_of_buf =4 /* RFC1001 len field */ + offset + (char *)hdr; +char *begin_of_buf = offset + (char *)iov->iov_base;int rc;if (!data)return -EINVAL ; - rc =validate_buf (offset, buffer_length, hdr, minbufsize); + rc =validate_iov (offset, buffer_length, iov, minbufsize);if (rc)return rc;@@ -2208,9 +2205,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, } } - rc =validate_and_copy_buf (le16_to_cpu (rsp->OutputBufferOffset), + rc =validate_and_copy_iov (le16_to_cpu (rsp->OutputBufferOffset),le32_to_cpu (rsp->OutputBufferLength), - &rsp->hdr, min_len, *data); + &rsp_iov, min_len, *data); qinf_exit:fs/cifs/smb2pdu.c +1
-1free_rsp_buf (resp_buftype, rsp);@@ -2279,7 +2276,7 @@ smb2_echo_callback(struct mid_q_entry *mid)unsigned int credits_received =1 ;if (mid->mid_state ==MID_RESPONSE_RECEIVED ) - credits_received =le16_to_cpu (rsp- >hdr.sync_hdr.CreditRequest); + credits_received =le16_to_cpu (rsp- >sync_hdr.CreditRequest);fs/cifs/smb2pdu.c +0
-1DeleteMidQEntry (mid);add_credits (server, credits_received,CIFS_ECHO_OP );@@ -2629,7 +2626,6 @@ SMB2_read(const unsigned int xid, structcifs_io_parms *io_parms, int resp_buftype, rc = -EACCES;struct smb2_read_plain_req *req =NULL ;struct smb2_read_rsp *rsp =NULL ; -struct smb2_sync_hdr *shdr;struct kvec iov[1 ];struct kvec rsp_iov;fs/cifs/smb2pdu.c +1
-3unsigned int total_len;@@ -2670,10 +2666,8 @@ SMB2_read(const unsigned int xid, structcifs_io_parms *io_parms, *nbytes =0 ; } - shdr =get_sync_hdr (rsp); -if (*buf) { -memcpy (*buf, (char *)shdr + rsp->DataOffset, *nbytes); +memcpy (*buf, (char *)rsp + rsp->DataOffset, *nbytes);free_rsp_buf (resp_buftype, rsp_iov.iov_base); }else if (resp_buftype !=CIFS_NO_BUFFER ) {fs/cifs/smb2pdu.c +1
-1*buf = rsp_iov.iov_base;@@ -2700,7 +2694,7 @@ smb2_writev_callback(struct mid_q_entry *mid) switch (mid->mid_state) { case MID_RESPONSE_RECEIVED: - credits_received =le16_to_cpu (rsp- >hdr.sync_hdr.CreditRequest); + credits_received = le16_to_cpu(rsp- >sync_hdr.CreditRequest); wdata->result = smb2_check_receive(mid, tcon->ses-Quoted 1 line
server, 0);
fs/cifs/smb2pdu.c +1
-1if (wdata->result !=0 )break ;@@ -3018,7 +3012,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, if (rc) {if (rc == -ENODATA && - rsp->hdr.sync_hdr.Status ==STATUS_NO_MORE_FILES ) { + rsp->sync_hdr.Status ==STATUS_NO_MORE_FILES ) { srch_inf->endOfSearch = true; rc =0 ;fs/cifs/smb2pdu.c +2
-2}@@ -3026,8 +3020,8 @@ SMB2_query_directory(const unsigned int xid,struct cifs_tcon *tcon, goto qdir_exit; } - rc =validate_buf (le16_to_cpu (rsp->OutputBufferOffset), -le32_to_cpu (rsp->OutputBufferLength), &rsp->hdr, + rc =validate_iov (le16_to_cpu (rsp->OutputBufferOffset), +le32_to_cpu (rsp->OutputBufferLength), &rsp_iov, info_buf_size);if (rc)fs/cifs/smb2pdu.c +3
-4goto qdir_exit;@@ -3041,10 +3035,9 @@ SMB2_query_directory(const unsigned int xid,struct cifs_tcon *tcon, cifs_buf_release(srch_inf->ntwrk_buf_start); } srch_inf->ntwrk_buf_start = (char *)rsp; - srch_inf->srch_entries_start = srch_inf->last_entry =4 /* rfclen */ + - (char *)&rsp->hdr +le16_to_cpu (rsp->OutputBufferOffset); -/* 4 for rfc1002 length field */ - end_of_smb =get_rfc1002_length (rsp) +4 + (char *)&rsp->hdr; + srch_inf->srch_entries_start = srch_inf->last_entry = + (char *)rsp +le16_to_cpu (rsp->OutputBufferOffset); + end_of_smb = rsp_iov.iov_len + (char *)rsp; srch_inf->entries_in_buffer = num_entries(srch_inf->srch_entries_start,
end_of_smb,fs/cifs/smb2pdu.c +1
-1&srch_inf->last_entry, info_buf_size);@@ -3280,7 +3273,7 @@ SMB2_oplock_break(const unsigned int xid, structcifs_tcon *tcon, __u8 oplock_level) { int rc; -struct smb2_oplock_break_req *req =NULL ; +struct smb2_oplock_break *req =NULL ;struct cifs_ses *ses = tcon->ses;int flags =CIFS_OBREAK_OP ;fs/cifs/smb2pdu.c +1
-1unsigned int total_len;@@ -3356,7 +3349,7 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level, req->InputBufferOffset =cpu_to_le16 (sizeof (struct smb2_query_info_req ) -1 ); req->OutputBufferLength =cpu_to_le32 ( - outbuf_len +sizeof (struct smb2_query_info_rsp ) -1 -4 ); + outbuf_len +sizeof (struct smb2_query_info_rsp ) -1 );fs/cifs/smb2pdu.c +4
-4iov->iov_base = (char *)req; iov->iov_len = total_len;@@ -3393,10 +3386,10 @@ SMB2_QFS_info(const unsigned int xid, structcifs_tcon *tcon, } rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; - info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ + -le16_to_cpu (rsp->OutputBufferOffset) + (char *)&rsp->hdr); - rc =validate_buf (le16_to_cpu (rsp->OutputBufferOffset), -le32_to_cpu (rsp->OutputBufferLength), &rsp->hdr, + info = (struct smb2_fs_full_size_info *)( +le16_to_cpu (rsp->OutputBufferOffset) + (char *)rsp); + rc =validate_iov (le16_to_cpu (rsp->OutputBufferOffset), +le32_to_cpu (rsp->OutputBufferLength), &rsp_iov,sizeof (struct smb2_fs_full_size_info ));if (!rc)fs/cifs/smb2pdu.c +6
-6copy_fs_info_to_kstatfs (info, fsdata);@@ -3451,20 +3444,20 @@ SMB2_QFS_attr(const unsigned int xid, structcifs_tcon *tcon, rsp_len =le32_to_cpu (rsp->OutputBufferLength); offset =le16_to_cpu (rsp->OutputBufferOffset); - rc =validate_buf (offset, rsp_len, &rsp->hdr, min_len); + rc =validate_iov (offset, rsp_len, &rsp_iov, min_len);if (rc) goto qfsattr_exit;if (level ==FS_ATTRIBUTE_INFORMATION ) -memcpy (&tcon->fsAttrInfo,4 /* RFC1001 len */ + offset - + (char *)&rsp->hdr, min_t(unsigned int, +memcpy (&tcon->fsAttrInfo, offset + + (char *)rsp, min_t(unsigned int, rsp_len, max_len));else if (level ==FS_DEVICE_INFORMATION ) -memcpy (&tcon->fsDevInfo,4 /* RFC1001 len */ + offset - + (char *)&rsp->hdr, sizeof(FILE_SYSTEM_DEVICE_INFO)); +memcpy (&tcon->fsDevInfo, offset + + (char *)rsp,sizeof (FILE_SYSTEM_DEVICE_INFO )); else if (level == FS_SECTOR_SIZE_INFORMATION) {struct smb3_fs_ss_info *ss_info = (struct smb3_fs_ss_info *) - (4 /* RFC1001 len */ + offset + (char *)&rsp->hdr); + (offset + (char *)rsp); tcon->ss_flags =le32_to_cpu (ss_info->Flags);fs/cifs/smb2pdu.c +0
-0tcon->perf_sector_size = le32_to_cpu(ss_info-Quoted 1 line
PhysicalBytesPerSectorForPerf);
fs/cifs/smb2pdu.h +0
-4@@ -122,25 +122,10 @@ struct smb2_sync_pdu {__le16 StructureSize2;/* size of wct area (varies, request specific) */ } __packed; -struct smb2_hdr { -__be32 smb2_buf_length;/* big endian on wire */ -/* length is only two or three bytes - with */ -/* one or two byte type preceding it that MBZ */
fs/cifs/smb2pdu.h +0
-11-struct smb2_sync_hdr sync_hdr; -} __packed; - -struct smb2_pdu { -struct smb2_hdr hdr; -__le16 StructureSize2;/* size of wct area (varies, request specific) */ -} __packed; -#define SMB3_AES128CMM_NONCE 11#define SMB3_AES128GCM_NONCE 12struct smb2_transform_hdr { -__be32 smb2_buf_length;/* big endian on wire */ -/* length is only two or three bytes - with -one or two byte type preceding it that MBZ */
fs/cifs/smb2pdu.h +19
-31__le32 ProtocolId;/* 0xFD 'S' 'M' 'B' */ __u8 Signature[16 ];__u8 Nonce[16 ];@@ -171,7 +156,7 @@ struct smb2_transform_hdr {#define SMB2_ERROR_STRUCTURE_SIZE2 cpu_to_le16(9)struct smb2_err_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;__le16 Reserved;/* MBZ */ __le32 ByteCount;/* even if zero, at least one byte follows */ @@ -259,7 +244,7 @@ struct smb2_encryption_neg_context { } __packed;struct smb2_negotiate_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 65 */ __le16 SecurityMode;__le16 DialectRevision;@@ -299,7 +284,7 @@ struct smb2_sess_setup_req {#define SMB2_SESSION_FLAG_IS_NULL 0x0002#define SMB2_SESSION_FLAG_ENCRYPT_DATA 0x0004struct smb2_sess_setup_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 9 */ __le16 SessionFlags;__le16 SecurityBufferOffset;@@ -314,7 +299,7 @@ struct smb2_logoff_req { } __packed;struct smb2_logoff_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 4 */ __le16 Reserved; } __packed;@@ -332,7 +317,7 @@ struct smb2_tree_connect_req { } __packed;struct smb2_tree_connect_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 16 */ __u8 ShareType;/* see below */ __u8 Reserved;@@ -381,7 +366,7 @@ struct smb2_tree_disconnect_req { } __packed;struct smb2_tree_disconnect_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 4 */ __le16 Reserved; } __packed;@@ -516,7 +501,7 @@ struct smb2_create_req { } __packed;struct smb2_create_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 89 */ __u8 OplockLevel;__u8 Reserved;@@ -771,7 +756,7 @@ struct smb2_ioctl_req { } __packed;struct smb2_ioctl_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 57 */ __u16 Reserved;__le32 CtlCode;@@ -798,7 +783,7 @@ struct smb2_close_req { } __packed;struct smb2_close_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* 60 */ __le16 Flags;__le32 Reserved;@@ -821,7 +806,7 @@ struct smb2_flush_req { } __packed;struct smb2_flush_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;__le16 Reserved; } __packed;@@ -853,7 +838,7 @@ struct smb2_read_plain_req { } __packed;struct smb2_read_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 17 */ __u8 DataOffset;__u8 Reserved;@@ -884,7 +869,7 @@ struct smb2_write_req { } __packed;struct smb2_write_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 17 */ __u8 DataOffset;__u8 Reserved;@@ -918,7 +903,7 @@ struct smb2_lock_req { } __packed;struct smb2_lock_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 4 */ __le16 Reserved; } __packed;@@ -930,7 +915,7 @@ struct smb2_echo_req { } __packed;struct smb2_echo_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 4 */ __u16 Reserved; } __packed;@@ -956,7 +941,7 @@ struct smb2_query_directory_req { } __packed;struct smb2_query_directory_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 9 */ __le16 OutputBufferOffset;__le32 OutputBufferLength;@@ -1005,7 +990,7 @@ struct smb2_query_info_req { } __packed;struct smb2_query_info_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 9 */ __le16 OutputBufferOffset;__le32 OutputBufferLength;@@ -1027,12 +1012,11 @@ struct smb2_set_info_req { } __packed;struct smb2_set_info_rsp { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 2 */ } __packed; -/* oplock break without an rfc1002 header */ -struct smb2_oplock_break_req { +struct smb2_oplock_break {struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 24 */ __u8 OplockLevel;@@ -1042,21 +1026,10 @@ struct smb2_oplock_break_req {__u64 VolatileFid; } __packed; -/* oplock break with an rfc1002 header */ -struct smb2_oplock_break_rsp { -struct smb2_hdr hdr; -__le16 StructureSize;/* Must be 24 */ -__u8 OplockLevel; -__u8 Reserved; -__le32 Reserved2; -__u64 PersistentFid; -__u64 VolatileFid; -} __packed; -#define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED cpu_to_le32(0x01)struct smb2_lease_break { -struct smb2_hdr hdr; +struct smb2_sync_hdr sync_hdr;__le16 StructureSize;/* Must be 44 */ __le16 Reserved;fs/cifs/smb2pdu.h +0
-0__le32 Flags;fs/cifs/smb2proto.h +2
-1@@ -37,7 +37,8 @@ extern int map_smb2_to_linux_error(char *buf, bool log_err);extern int smb2_check_message (char *buf,unsigned int length,struct TCP_Server_Info *server);extern unsigned int smb2_calc_size (void *buf); -extern char *smb2_get_data_area_len (int *off,int *len,struct smb2_hdr *hdr); +extern char *smb2_get_data_area_len (int *off,int *len, +struct smb2_sync_hdr *shdr); extern __le16 *cifs_convert_path_to_utf16(const char *from,fs/cifs/smb2proto.h +1
-1struct cifs_sb_info *cifs_sb);@@ -122,7 +123,7 @@ extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);extern int SMB2_open (const unsigned int xid,struct cifs_open_parms *oparms,__le16 *path,__u8 *oplock,struct smb2_file_all_info *buf, -struct smb2_err_rsp **err_buf); +struct kvec *err_iov); extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,fs/cifs/smb2proto.h +0
-0u64 persistent_fid, u64 volatile_fid, u32 opcode, bool is_fsctl, bool use_ipc,fs/cifs/smb2transport.c +3
-3@@ -624,10 +624,10 @@ smb2_check_receive(struct mid_q_entry *mid,struct TCP_Server_Info *server, struct smb_rqst rqst = { .rq_iov = iov, .rq_nvec =2 }; - iov[0 ].iov_base = (char *)mid->resp_buf; + iov[0 ].iov_base =NULL ; iov[0 ].iov_len =4 ; - iov[1 ].iov_base = (char *)mid->resp_buf +4 ; - iov[1 ].iov_len = len; + iov[1 ].iov_base = (char *)mid->resp_buf; + iov[1 ].iov_len = server->total_size;dump_smb (mid->resp_buf,min_t (u32,80 , len));fs/cifs/smb2transport.c +0
-0/* convert the length into a more usable form */ fs/cifs/transport.c +3
-1@@ -779,7 +779,9 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, buf = (char *)midQ->resp_buf; resp_iov->iov_base = buf; - resp_iov->iov_len =get_rfc1002_length (buf) +4 ; + resp_iov->iov_len = ses->server->total_size + + ses->server->vals->header_preamble_size; +if (midQ->large_buf) *resp_buf_type =CIFS_LARGE_BUFFER ;else
--
2.13.3--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at
https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvger.ke
rnel.org%2Fmajordomo- info.html&data=02%7C01%7Clongli%40microsoft.com%7C87c5835933204099 df5808d552312c01%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C63 6505293516357233&sdata=krI0mR4ST9isrQpCQ5xQ4yAbkqEf10SYaZb4FP%2B k2GA%3D&reserved=0
PATCH 2/2 cifs: update multiplex loop to handle compounded responses
In reply to a message not in the archive--- fs/cifs/cifsglob.h | 2 +- fs/cifs/connect.c | 18 +++++++++++++++--- fs/cifs/smb2ops.c | 12 ++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-)
fs/cifs/cifsglob.h +1 -1
@@ -449,7 +449,7 @@ struct smb_version_operations { struct mid_q_entry **);enum securityEnum (*select_sectype)(struct TCP_Server_Info *,enum securityEnum ); - +int (*next_header)(char *); };struct smb_version_values {
fs/cifs/connect.c +15 -3
@@ -840,6 +840,7 @@ cifs_demultiplex_thread(void *p)int length;struct TCP_Server_Info *server = p;unsigned int pdu_length; +unsigned int next_offset;char *buf =NULL ;struct task_struct *task_to_wake =NULL ;struct mid_q_entry *mid_entry;
@@ -877,17 +878,18 @@ cifs_demultiplex_thread(void *p)* so we can now interpret the length field. */ pdu_length =get_rfc1002_length (buf); +next_pdu: server->total_size = pdu_length; -cifs_dbg (FYI ,"RFC1002 header 0x%x\n" , pdu_length); +cifs_dbg (FYI ,"RFC1002 header 0x%x\n" , server->total_size);if (!is_smb_response (server, buf[0 ]))continue ;/* make sure we have enough to get to the MID */ -if (pdu_length <HEADER_SIZE (server) -1 - +if (server->total_size <HEADER_SIZE (server) -1 - server->vals->header_preamble_size) {cifs_dbg (VFS ,"SMB response too short (%u bytes)\n" , - pdu_length); + server->total_size);cifs_reconnect (server);wake_up (&server->response_q);continue ;
@@ -902,6 +904,12 @@ cifs_demultiplex_thread(void *p)continue ; server->total_read += length; +if (server->ops->next_header) { + next_offset = server->ops->next_header (buf); +if (next_offset) + server->total_size = next_offset; + } +if (server->ops->is_transform_hdr && server->ops->receive_transform && server->ops->is_transform_hdr (buf)) {
@@ -947,6 +955,10 @@ cifs_demultiplex_thread(void *p)cifs_dump_mids (server);#endif /* CIFS_DEBUG2 */ +if (pdu_length > server->total_size) { + pdu_length -= server->total_size; + goto next_pdu; + } } }/* end while !EXITING */
fs/cifs/smb2ops.c +12 -0
@@ -2710,6 +2710,14 @@ smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid) NULL, 0, 0); } +static int +smb2_next_header (char *buf) +{ +struct smb2_sync_hdr *hdr = (struct smb2_sync_hdr *)buf; + +return le32_to_cpu (hdr->NextCommand); +} +struct smb_version_operations smb20_operations = { .compare_fids = smb2_compare_fids, .setup_request = smb2_setup_request,
@@ -2801,6 +2809,7 @@ struct smb_version_operations smb20_operations = { .get_acl_by_fid = get_smb2_acl_by_fid, .set_acl = set_smb2_acl,#endif /* CIFS_ACL */ + .next_header = smb2_next_header, };struct smb_version_operations smb21_operations = {
@@ -2895,6 +2904,7 @@ struct smb_version_operations smb21_operations = { .get_acl_by_fid = get_smb2_acl_by_fid, .set_acl = set_smb2_acl,#endif /* CIFS_ACL */ + .next_header = smb2_next_header, };struct smb_version_operations smb30_operations = {
@@ -2999,6 +3009,7 @@ struct smb_version_operations smb30_operations = { .get_acl_by_fid = get_smb2_acl_by_fid, .set_acl = set_smb2_acl,#endif /* CIFS_ACL */ + .next_header = smb2_next_header, };#ifdef CONFIG_CIFS_SMB311
@@ -3099,6 +3110,7 @@ struct smb_version_operations smb311_operations = { .query_all_EAs = smb2_query_eas, .set_EA = smb2_set_ea,#endif /* CIFS_XATTR */ + .next_header = smb2_next_header, };#endif /* CIFS_SMB311 */
Signature · 1 line
2.13.3
Quoted 27 lines · Ronnie Sahlberg
Steve, all
Please review but do not merge.
This is based on current sfrench/for-next and is the final step before we can start doing compounding.The patch will break the soon to be merged SMBD support from Long Li so do not merge this. I suggest we wait until Long's patches are merged and I will rebase, and fixup the SMBD parts that this breaks.
The first patch removes the rfc1002 length field from all SMB2 responses. Unfortunately it is not easy to do this in a set of incremental patches as opposed to one single big patch since in the demultiplex loop we can not really distinguish between different response structures until we have read the full SMB2 header, and in order to read the header we must know whether there should be a rfc1002 length there or not. I.e. chicken and egg.
During developmnet of these patches I did have a series that performed the change one structure at a time but it is very ugly, doing memcpy to strip off the header when there should be none
and converting several helper functions to check their char*buf arguments whether it looked like the buffer started with a rfc1002 header or not. Very ugly and not I think something we want in the upstream commit history but if someone really wants to see the "individual change for each response structure" I could make those intermediate patchsets available.
Quoted 5 lines
It works for basic and manual testing. What remains is to ensure that SMBD is updated to not have to prepend the length field any more once those patches go in, and also SMB3 encryption.
I have not had a chance to test it so if someone could help here would be awesome.
I have not had a chance to test it, WITH SMB3 ENCRYPTION, so ...
Quoted 9 lines
The second patch updates the demultiplex loop so that it can handle compounded responses.
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html