Message ID | 20180508235537.31416-3-lsahlber@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
This is the most complex patch in the series. It mostly consists of changing the smb3 transforms header and encryption code to handle the fact that we no longer have an iov for the 4 byte preamble. The patch does a few different things but should not be too bad to review. Since so much of it consists of the smb3 transform changes I am not sure we can split this down much more in any meaningful way, but it is at least not >2k lines any more :-) On Wed, May 9, 2018 at 9:55 AM, Ronnie Sahlberg <lsahlber@redhat.com> wrote: > 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. > > Update the smb3 transform header processing that we no longer have > a rfc1002 header at the start of this structure. > > Update smb2_readv_callback to accomodate that the first iovector in the > response is no the smb2 header and no longer a rfc1002 header. > > Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> > --- > fs/cifs/connect.c | 6 ++- > fs/cifs/smb2ops.c | 112 ++++++++++++++++++++++++++++-------------------- > fs/cifs/smb2pdu.c | 20 +++------ > fs/cifs/smb2pdu.h | 6 --- > fs/cifs/smb2transport.c | 10 ++--- > 5 files changed, 81 insertions(+), 73 deletions(-) > > diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c > index 83b0234d443c..ba4b1c705c88 100644 > --- a/fs/cifs/connect.c > +++ b/fs/cifs/connect.c > @@ -877,7 +877,11 @@ 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, > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c > index ceaa358723f0..c54ebc6399cb 100644 > --- a/fs/cifs/smb2ops.c > +++ b/fs/cifs/smb2ops.c > @@ -2117,12 +2117,11 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile) > } > > static void > -fill_transform_hdr(struct TCP_Server_Info *server, > - struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq) > +fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len, > + struct smb_rqst *old_rq) > { > struct smb2_sync_hdr *shdr = > (struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base; > - unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base); > > memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr)); > tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM; > @@ -2130,8 +2129,6 @@ fill_transform_hdr(struct TCP_Server_Info *server, > 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) - server->vals->header_preamble_size); > - inc_rfc1001_len(tr_hdr, orig_len); > } > > /* We can not use the normal sg_set_buf() as we will sometimes pass a > @@ -2143,11 +2140,16 @@ static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf, > sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf)); > } > > +/* Assumes: > + * rqst->rq_iov[0] is rfc1002 length > + * rqst->rq_iov[1] is tranform header > + * rqst->rq_iov[2+] data to be encrypted/decrypted > + */ > 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 sg_len = rqst->rq_nvec + rqst->rq_npages; > + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; > struct scatterlist *sg; > unsigned int i; > unsigned int j; > @@ -2157,10 +2159,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign) > return NULL; > > sg_init_table(sg, sg_len); > - smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len); > - for (i = 1; i < rqst->rq_nvec; i++) > - smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base, > - rqst->rq_iov[i].iov_len); > + smb2_sg_set_buf(&sg[0], rqst->rq_iov[1].iov_base + 20, assoc_data_len); > + for (i = 1; i < rqst->rq_nvec - 1; i++) > + smb2_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; > @@ -2192,9 +2194,10 @@ 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 > @@ -2289,6 +2292,10 @@ 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, > struct smb_rqst *old_rq) > @@ -2297,6 +2304,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, > struct page **pages; > struct smb2_transform_hdr *tr_hdr; > unsigned int npages = old_rq->rq_npages; > + unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base); > int i; > int rc = -ENOMEM; > > @@ -2315,24 +2323,34 @@ 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 */ > + iov[0].iov_base = old_rq->rq_iov[0].iov_base; > + iov[0].iov_len = 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_transform_hdr(server, 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); > + /* fill the 2nd iov with a transform header */ > + fill_transform_hdr(tr_hdr, orig_len, old_rq); > + new_rq->rq_iov[1].iov_base = tr_hdr; > + new_rq->rq_iov[1].iov_len = sizeof(struct smb2_transform_hdr); > + > + /* Update rfc1002 header */ > + inc_rfc1001_len(new_rq->rq_iov[0].iov_base, > + sizeof(struct smb2_transform_hdr)); > > /* copy pages form the old */ > for (i = 0; i < npages; i++) { > @@ -2372,7 +2390,7 @@ smb3_free_transform_rq(struct smb_rqst *rqst) > put_page(rqst->rq_pages[i]); > kfree(rqst->rq_pages); > /* free transform header */ > - kfree(rqst->rq_iov[0].iov_base); > + kfree(rqst->rq_iov[1].iov_base); > kfree(rqst->rq_iov); > } > > @@ -2389,18 +2407,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; > rqst.rq_pagesz = PAGE_SIZE; > @@ -2412,10 +2431,9 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf, > if (rc) > return rc; > > - memmove(buf + server->vals->header_preamble_size, 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 + server->vals->header_preamble_size; > + memmove(buf + server->vals->header_preamble_size, iov[2].iov_base, buf_data_size); > + > + server->total_read = buf_data_size + page_data_size; > > return rc; > } > @@ -3169,8 +3187,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 = 4, > + .header_size = sizeof(struct smb2_sync_hdr), > + .header_preamble_size = 0, > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > @@ -3190,8 +3208,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 = 4, > + .header_size = sizeof(struct smb2_sync_hdr), > + .header_preamble_size = 0, > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > @@ -3211,8 +3229,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 = 4, > + .header_size = sizeof(struct smb2_sync_hdr), > + .header_preamble_size = 0, > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > @@ -3232,8 +3250,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 = 4, > + .header_size = sizeof(struct smb2_sync_hdr), > + .header_preamble_size = 0, > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > @@ -3253,8 +3271,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 = 4, > + .header_size = sizeof(struct smb2_sync_hdr), > + .header_preamble_size = 0, > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > @@ -3274,8 +3292,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 = 4, > + .header_size = sizeof(struct smb2_sync_hdr), > + .header_preamble_size = 0, > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > @@ -3296,8 +3314,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 = 4, > + .header_size = sizeof(struct smb2_sync_hdr), > + .header_preamble_size = 0, > .max_header_size = MAX_SMB2_HDR_SIZE, > .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, > .lock_cmd = SMB2_LOCK, > diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c > index ef77df4ebdf3..35d06980a8dd 100644 > --- a/fs/cifs/smb2pdu.c > +++ b/fs/cifs/smb2pdu.c > @@ -1996,7 +1996,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]; > struct kvec rsp_iov; > @@ -2117,7 +2116,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, > le32_to_cpu(rsp->OutputOffset)); > *plen = 0; > @@ -2131,8 +2130,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: > free_rsp_buf(resp_buftype, rsp); > return rc; > @@ -2660,7 +2658,7 @@ smb2_readv_callback(struct mid_q_entry *mid) > struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); > struct TCP_Server_Info *server = tcon->ses->server; > struct smb2_sync_hdr *shdr = > - (struct smb2_sync_hdr *)rdata->iov[1].iov_base; > + (struct smb2_sync_hdr *)rdata->iov[0].iov_base; > unsigned int credits_received = 1; > struct smb_rqst rqst = { .rq_iov = rdata->iov, > .rq_nvec = 2, > @@ -2806,7 +2804,6 @@ SMB2_read(const unsigned int xid, struct cifs_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; > unsigned int total_len; > @@ -2847,10 +2844,8 @@ SMB2_read(const unsigned int xid, struct cifs_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) { > *buf = rsp_iov.iov_base; > @@ -3277,10 +3272,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, > &srch_inf->last_entry, info_buf_size); > diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h > index d28f358022c5..32eb7b51b8d4 100644 > --- a/fs/cifs/smb2pdu.h > +++ b/fs/cifs/smb2pdu.h > @@ -123,9 +123,6 @@ struct smb2_sync_pdu { > } __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 */ > struct smb2_sync_hdr sync_hdr; > } __packed; > > @@ -138,9 +135,6 @@ struct smb2_pdu { > #define SMB3_AES128GCM_NONCE 12 > > struct 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 */ > __le32 ProtocolId; /* 0xFD 'S' 'M' 'B' */ > __u8 Signature[16]; > __u8 Nonce[16]; > diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c > index 8806f3f76c1d..2c671123a6bf 100644 > --- a/fs/cifs/smb2transport.c > +++ b/fs/cifs/smb2transport.c > @@ -480,7 +480,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) > unsigned int rc; > char server_response_sig[16]; > struct smb2_sync_hdr *shdr = > - (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base; > + (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; > > if ((shdr->Command == SMB2_NEGOTIATE) || > (shdr->Command == SMB2_SESSION_SETUP) || > @@ -605,14 +605,12 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, > bool log_error) > { > unsigned int len = mid->resp_buf_size; > - struct kvec iov[2]; > + struct kvec iov[1]; > struct smb_rqst rqst = { .rq_iov = iov, > - .rq_nvec = 2 }; > + .rq_nvec = 1 }; > > iov[0].iov_base = (char *)mid->resp_buf; > - iov[0].iov_len = 4; > - iov[1].iov_base = (char *)mid->resp_buf + 4; > - iov[1].iov_len = len; > + iov[0].iov_len = len; > > dump_smb(mid->resp_buf, min_t(u32, 80, len)); > /* convert the length into a more usable form */ > -- > 2.13.3 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 83b0234d443c..ba4b1c705c88 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -877,7 +877,11 @@ 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, diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index ceaa358723f0..c54ebc6399cb 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2117,12 +2117,11 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile) } static void -fill_transform_hdr(struct TCP_Server_Info *server, - struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq) +fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len, + struct smb_rqst *old_rq) { struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base; - unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base); memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr)); tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM; @@ -2130,8 +2129,6 @@ fill_transform_hdr(struct TCP_Server_Info *server, 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) - server->vals->header_preamble_size); - inc_rfc1001_len(tr_hdr, orig_len); } /* We can not use the normal sg_set_buf() as we will sometimes pass a @@ -2143,11 +2140,16 @@ static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf, sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf)); } +/* Assumes: + * rqst->rq_iov[0] is rfc1002 length + * rqst->rq_iov[1] is tranform header + * rqst->rq_iov[2+] data to be encrypted/decrypted + */ 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 sg_len = rqst->rq_nvec + rqst->rq_npages; + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; struct scatterlist *sg; unsigned int i; unsigned int j; @@ -2157,10 +2159,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign) return NULL; sg_init_table(sg, sg_len); - smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len); - for (i = 1; i < rqst->rq_nvec; i++) - smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base, - rqst->rq_iov[i].iov_len); + smb2_sg_set_buf(&sg[0], rqst->rq_iov[1].iov_base + 20, assoc_data_len); + for (i = 1; i < rqst->rq_nvec - 1; i++) + smb2_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; @@ -2192,9 +2194,10 @@ 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 @@ -2289,6 +2292,10 @@ 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, struct smb_rqst *old_rq) @@ -2297,6 +2304,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, struct page **pages; struct smb2_transform_hdr *tr_hdr; unsigned int npages = old_rq->rq_npages; + unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base); int i; int rc = -ENOMEM; @@ -2315,24 +2323,34 @@ 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 */ + iov[0].iov_base = old_rq->rq_iov[0].iov_base; + iov[0].iov_len = 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_transform_hdr(server, 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); + /* fill the 2nd iov with a transform header */ + fill_transform_hdr(tr_hdr, orig_len, old_rq); + new_rq->rq_iov[1].iov_base = tr_hdr; + new_rq->rq_iov[1].iov_len = sizeof(struct smb2_transform_hdr); + + /* Update rfc1002 header */ + inc_rfc1001_len(new_rq->rq_iov[0].iov_base, + sizeof(struct smb2_transform_hdr)); /* copy pages form the old */ for (i = 0; i < npages; i++) { @@ -2372,7 +2390,7 @@ smb3_free_transform_rq(struct smb_rqst *rqst) put_page(rqst->rq_pages[i]); kfree(rqst->rq_pages); /* free transform header */ - kfree(rqst->rq_iov[0].iov_base); + kfree(rqst->rq_iov[1].iov_base); kfree(rqst->rq_iov); } @@ -2389,18 +2407,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; rqst.rq_pagesz = PAGE_SIZE; @@ -2412,10 +2431,9 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf, if (rc) return rc; - memmove(buf + server->vals->header_preamble_size, 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 + server->vals->header_preamble_size; + memmove(buf + server->vals->header_preamble_size, iov[2].iov_base, buf_data_size); + + server->total_read = buf_data_size + page_data_size; return rc; } @@ -3169,8 +3187,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 = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, @@ -3190,8 +3208,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 = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, @@ -3211,8 +3229,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 = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, @@ -3232,8 +3250,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 = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, @@ -3253,8 +3271,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 = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, @@ -3274,8 +3292,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 = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, @@ -3296,8 +3314,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 = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index ef77df4ebdf3..35d06980a8dd 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1996,7 +1996,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]; struct kvec rsp_iov; @@ -2117,7 +2116,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, le32_to_cpu(rsp->OutputOffset)); *plen = 0; @@ -2131,8 +2130,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: free_rsp_buf(resp_buftype, rsp); return rc; @@ -2660,7 +2658,7 @@ smb2_readv_callback(struct mid_q_entry *mid) struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); struct TCP_Server_Info *server = tcon->ses->server; struct smb2_sync_hdr *shdr = - (struct smb2_sync_hdr *)rdata->iov[1].iov_base; + (struct smb2_sync_hdr *)rdata->iov[0].iov_base; unsigned int credits_received = 1; struct smb_rqst rqst = { .rq_iov = rdata->iov, .rq_nvec = 2, @@ -2806,7 +2804,6 @@ SMB2_read(const unsigned int xid, struct cifs_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; unsigned int total_len; @@ -2847,10 +2844,8 @@ SMB2_read(const unsigned int xid, struct cifs_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) { *buf = rsp_iov.iov_base; @@ -3277,10 +3272,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, &srch_inf->last_entry, info_buf_size); diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index d28f358022c5..32eb7b51b8d4 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -123,9 +123,6 @@ struct smb2_sync_pdu { } __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 */ struct smb2_sync_hdr sync_hdr; } __packed; @@ -138,9 +135,6 @@ struct smb2_pdu { #define SMB3_AES128GCM_NONCE 12 struct 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 */ __le32 ProtocolId; /* 0xFD 'S' 'M' 'B' */ __u8 Signature[16]; __u8 Nonce[16]; diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 8806f3f76c1d..2c671123a6bf 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -480,7 +480,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) unsigned int rc; char server_response_sig[16]; struct smb2_sync_hdr *shdr = - (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base; + (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; if ((shdr->Command == SMB2_NEGOTIATE) || (shdr->Command == SMB2_SESSION_SETUP) || @@ -605,14 +605,12 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, bool log_error) { unsigned int len = mid->resp_buf_size; - struct kvec iov[2]; + struct kvec iov[1]; struct smb_rqst rqst = { .rq_iov = iov, - .rq_nvec = 2 }; + .rq_nvec = 1 }; iov[0].iov_base = (char *)mid->resp_buf; - iov[0].iov_len = 4; - iov[1].iov_base = (char *)mid->resp_buf + 4; - iov[1].iov_len = len; + iov[0].iov_len = len; dump_smb(mid->resp_buf, min_t(u32, 80, len)); /* convert the length into a more usable form */
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. Update the smb3 transform header processing that we no longer have a rfc1002 header at the start of this structure. Update smb2_readv_callback to accomodate that the first iovector in the response is no the smb2 header and no longer a rfc1002 header. Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> --- fs/cifs/connect.c | 6 ++- fs/cifs/smb2ops.c | 112 ++++++++++++++++++++++++++++-------------------- fs/cifs/smb2pdu.c | 20 +++------ fs/cifs/smb2pdu.h | 6 --- fs/cifs/smb2transport.c | 10 ++--- 5 files changed, 81 insertions(+), 73 deletions(-)