From patchwork Tue Feb 13 04:42:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872602 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVKp5K2Vz9sBZ for ; Tue, 13 Feb 2018 15:43:42 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933399AbeBMEnm (ORCPT ); Mon, 12 Feb 2018 23:43:42 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:33264 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933378AbeBMEnl (ORCPT ); Mon, 12 Feb 2018 23:43:41 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 98A7E80125D6; Tue, 13 Feb 2018 04:43:40 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1BDF910075ED; Tue, 13 Feb 2018 04:43:36 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 01/14] cifs: remove rfc1002 header from all SMB2 response structures Date: Tue, 13 Feb 2018 15:42:21 +1100 Message-Id: <20180213044234.18364-2-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 13 Feb 2018 04:43:40 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 13 Feb 2018 04:43:40 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org 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. Signed-off-by: Ronnie Sahlberg --- fs/cifs/cifsglob.h | 2 + fs/cifs/cifssmb.c | 9 ++- fs/cifs/connect.c | 32 ++++++--- fs/cifs/misc.c | 2 +- fs/cifs/smb1ops.c | 1 + fs/cifs/smb2glob.h | 5 -- fs/cifs/smb2maperror.c | 8 ++- fs/cifs/smb2misc.c | 111 +++++++++++++++---------------- fs/cifs/smb2ops.c | 171 ++++++++++++++++++++++++++++++------------------ 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, 277 insertions(+), 249 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 3fb1a2fe1ea9..14db722c4b0d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -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 */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 35dc5bf01ee2..114e2a7ca77f 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -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 diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 64be6f9e54a2..18a1cb4f2330 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -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,18 +894,20 @@ 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; if (server->ops->is_transform_hdr && server->ops->receive_transform && - server->ops->is_transform_hdr(buf)) { + server->ops->is_transform_hdr(buf)) length = server->ops->receive_transform(server, &mid_entry); - } else { + else { mid_entry = server->ops->find_mid(server, buf); if (!mid_entry || !mid_entry->receive) diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index eea93ac15ef0..37022a34982b 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -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 - diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index a723df3e0197..4c87265050fc 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -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), diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h index 401a5d856636..0ffa18094335 100644 --- a/fs/cifs/smb2glob.h +++ b/fs/cifs/smb2glob.h @@ -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 */ diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c index 62c88dfed57b..8484058346cd 100644 --- a/fs/cifs/smb2maperror.c +++ b/fs/cifs/smb2maperror.c @@ -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; diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 76d03abaa38c..3bed50ba0d2f 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -96,23 +96,23 @@ 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; /* * Add function to do table lookup of StructureSize by command * ie Validate the wct via smb2_struct_sizes table above */ - if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { struct smb2_transform_hdr *thdr = (struct smb2_transform_hdr *)buf; @@ -136,8 +136,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; /* @@ -150,7 +150,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", mid); return 1; @@ -189,26 +189,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; /* 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 +212,10 @@ smb2_check_message(char *buf, unsigned int length, 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; } @@ -262,15 +256,14 @@ static const bool has_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 && - (((struct smb2_err_rsp *)hdr)->StructureSize) == + (((struct smb2_err_rsp *)shdr)->StructureSize) == SMB2_ERROR_STRUCTURE_SIZE2) return NULL; @@ -282,42 +275,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)->DataLength); + /* TODO: is this a bug ? */ + *off = ((struct smb2_read_rsp *)shdr)->DataOffset; + *len = le32_to_cpu(((struct smb2_read_rsp *)shdr)->DataLength); break; case SMB2_QUERY_DIRECTORY: *off = le16_to_cpu( - ((struct smb2_query_directory_rsp *)hdr)->OutputBufferOffset); + ((struct smb2_query_directory_rsp *)shdr)->OutputBufferOffset); *len = le32_to_cpu( - ((struct smb2_query_directory_rsp *)hdr)->OutputBufferLength); + ((struct smb2_query_directory_rsp *)shdr)->OutputBufferLength); break; case SMB2_IOCTL: *off = le32_to_cpu( - ((struct smb2_ioctl_rsp *)hdr)->OutputOffset); - *len = le32_to_cpu(((struct smb2_ioctl_rsp *)hdr)->OutputCount); + ((struct smb2_ioctl_rsp *)shdr)->OutputOffset); + *len = le32_to_cpu( + ((struct smb2_ioctl_rsp *)shdr)->OutputCount); break; case SMB2_CHANGE_NOTIFY: default: @@ -362,13 +357,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); /* * StructureSize2, ie length of fixed parameter area has already @@ -379,7 +377,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); if (data_length > 0) { @@ -387,15 +385,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; } } calc_size_exit: @@ -578,7 +575,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; struct cifs_ses *ses; struct cifs_tcon *tcon; @@ -587,7 +584,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; if (rsp->StructureSize != @@ -678,11 +675,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) return 0; diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index ed88ab8a4774..5cfcc8c53a56 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -122,7 +122,8 @@ 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 = (struct smb2_sync_hdr *)buf; return le16_to_cpu(shdr->CreditRequest); } @@ -189,8 +190,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 +219,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->MessageId, @@ -1230,7 +1237,9 @@ smb2_close_dir(const unsigned int xid, struct cifs_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; if (shdr->Status != STATUS_PENDING) return false; @@ -1248,7 +1257,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) return false; @@ -1444,6 +1455,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_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; unsigned int sub_len; @@ -1464,15 +1476,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) || - 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 +1498,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) { kfree(utf16_path); return -ENOENT; @@ -2045,11 +2058,11 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile) } static void -fill_transform_hdr(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; @@ -2057,15 +2070,18 @@ 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); } +/* 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; @@ -2075,10 +2091,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); - 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[0], rqst->rq_iov[1].iov_base + 20, assoc_data_len); + for (i = 1; i < rqst->rq_nvec - 1; i++) + 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 +2126,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; + (struct smb2_transform_hdr *)rqst->rq_iov[1].iov_base; + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; int rc = 0; struct scatterlist *sg; u8 sign[SMB2_SIGNATURE_SIZE] = {}; @@ -2132,6 +2149,7 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) struct crypto_aead *tfm; unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize); + /* Fixme compounding: get rid of iov[0] */ rc = smb2_get_enc_key(server, tr_hdr->SessionId, enc, key); if (rc) { cifs_dbg(VFS, "%s: Could not get %scryption key\n", __func__, @@ -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, struct smb_rqst *old_rq) @@ -2215,6 +2236,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; @@ -2233,24 +2255,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(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++) { @@ -2290,7 +2322,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); } @@ -2307,18 +2339,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; @@ -2330,10 +2363,9 @@ 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[2].iov_base, buf_data_size); + + server->total_read = buf_data_size + page_data_size; return rc; } @@ -2406,12 +2438,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"); return -ENOTSUPP; @@ -2529,11 +2563,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_size; 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); @@ -2541,7 +2575,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 +2602,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) goto free_pages; @@ -2600,12 +2634,12 @@ receive_encrypted_standard(struct TCP_Server_Info *server, { int length; char *buf = server->smallbuf; - unsigned int pdu_length = get_rfc1002_length(buf); + unsigned int pdu_length = server->total_size; 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); buf = server->bigbuf; @@ -2613,12 +2647,12 @@ receive_encrypted_standard(struct TCP_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); if (length) return length; @@ -2643,12 +2677,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_size; 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)) { cifs_dbg(VFS, "Transform message is too small (%u)\n", pdu_length); cifs_reconnect(server); @@ -2656,14 +2690,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); return receive_encrypted_standard(server, mid); @@ -3078,7 +3112,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 +3133,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 +3154,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 +3175,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 +3196,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 +3217,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 +3239,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, diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index c0dc0491af93..ad178150fbf3 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -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); /* * 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) != le16_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: @@ -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); rc = 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)); if ((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) { cifs_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); remaining = 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) { struct 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; } @@ -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]; struct 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, le32_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: free_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 int buffer_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: free_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); DeleteMidQEntry(mid); add_credits(server, credits_received, CIFS_ECHO_OP); @@ -2629,7 +2626,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; @@ -2670,10 +2666,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; @@ -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->server, 0); if (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; } @@ -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) goto 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, &srch_inf->last_entry, info_buf_size); @@ -3280,7 +3273,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_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; unsigned 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); iov->iov_base = (char *)req; iov->iov_len = total_len; @@ -3393,10 +3386,10 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_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) copy_fs_info_to_kstatfs(info, fsdata); @@ -3451,20 +3444,20 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_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); tcon->perf_sector_size = le32_to_cpu(ss_info->PhysicalBytesPerSectorForPerf); diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 19d34881815f..91fd17f5c2eb 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -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 */ - 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 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]; @@ -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 0x0004 struct 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; __le32 Flags; diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index e9ab5227e7a8..089a6ef936b8 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -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, diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 99493946e2f9..cf37c6651bf6 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -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 */ diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 510f41a435c8..5cecf67af8f1 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -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 From patchwork Tue Feb 13 04:42:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872603 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVKt105pz9sBZ for ; Tue, 13 Feb 2018 15:43:46 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933417AbeBMEnp (ORCPT ); Mon, 12 Feb 2018 23:43:45 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:39760 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933378AbeBMEnp (ORCPT ); Mon, 12 Feb 2018 23:43:45 -0500 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E55B04022909; Tue, 13 Feb 2018 04:43:44 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0D67B2024CA1; Tue, 13 Feb 2018 04:43:42 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 02/14] cifs: update multiplex loop to handle compounded responses Date: Tue, 13 Feb 2018 15:42:22 +1100 Message-Id: <20180213044234.18364-3-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 13 Feb 2018 04:43:44 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 13 Feb 2018 04:43:44 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Signed-off-by: Ronnie Sahlberg --- fs/cifs/cifsglob.h | 2 +- fs/cifs/connect.c | 26 +++++++++++++++++++++----- fs/cifs/smb2misc.c | 1 + fs/cifs/smb2ops.c | 22 ++++++++++++++++++++++ 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 14db722c4b0d..18a961d32e0c 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -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 { diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 18a1cb4f2330..a1f84da91eaa 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -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); - 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; +next_pdu: + server->total_size = pdu_length; /* 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)) @@ -946,7 +954,15 @@ cifs_demultiplex_thread(void *p) server->ops->dump_detail(buf); cifs_dump_mids(server); #endif /* CIFS_DEBUG2 */ - + } + if (pdu_length > server->total_size) { + if (!allocate_buffers(server)) + continue; + pdu_length -= server->total_size; + server->total_read = 0; + server->large_buf = false; + buf = server->smallbuf; + goto next_pdu; } } /* end while !EXITING */ diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 3bed50ba0d2f..23ac9dc9acf0 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -209,6 +209,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) * MacOS server pads after SMB2.1 write response with 3 bytes * of junk. Other servers match RFC1001 len to actual * SMB2/SMB3 frame length (header + smb2 response specific data) + * Some windows servers do too when compounding is used. * Log the server error (once), but allow it and continue * since the frame is parseable. */ diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 5cfcc8c53a56..1c60b4e64656 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2712,6 +2712,24 @@ 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; + struct smb2_transform_hdr *t_hdr = (struct smb2_transform_hdr *)buf; + + /* FIXME: compounding. + * How does compounding work with smb3 encryption? + * For now, assume that we will have one transform header for each + * smb2 header (and assume that smb2->NextOffset is 0 for all of them.) + */ + if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) + return sizeof(struct smb2_transform_hdr) + + le32_to_cpu(t_hdr->OriginalMessageSize); + + return le32_to_cpu(hdr->NextCommand); +} + struct smb_version_operations smb20_operations = { .compare_fids = smb2_compare_fids, .setup_request = smb2_setup_request, @@ -2803,6 +2821,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 = { @@ -2897,6 +2916,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 = { @@ -3001,6 +3021,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 @@ -3101,6 +3122,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 */ From patchwork Tue Feb 13 04:42:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872591 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVJn0sK1z9sBZ for ; Tue, 13 Feb 2018 15:42:48 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933378AbeBMEmr (ORCPT ); Mon, 12 Feb 2018 23:42:47 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:39742 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933218AbeBMEmq (ORCPT ); Mon, 12 Feb 2018 23:42:46 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 59CC54022909; Tue, 13 Feb 2018 04:42:46 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1792FAE7C8; Tue, 13 Feb 2018 04:42:44 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 03/14] cifs: push rfc1002 generation down the stack Date: Tue, 13 Feb 2018 15:42:23 +1100 Message-Id: <20180213044234.18364-4-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 13 Feb 2018 04:42:46 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 13 Feb 2018 04:42:46 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Move the generation of the 4 byte length field down the stack and generate it immediately before we start writing the data to the socket. Signed-off-by: Ronnie Sahlberg --- fs/cifs/cifsencrypt.c | 10 +++++-- fs/cifs/smb2ops.c | 73 ++++++++++++++++++++----------------------------- fs/cifs/smb2pdu.c | 34 +++++++---------------- fs/cifs/smb2transport.c | 22 +++++++-------- fs/cifs/transport.c | 73 ++++++++++++++++++------------------------------- 5 files changed, 85 insertions(+), 127 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 68abbb0db608..6bc175f44b8d 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -76,8 +76,14 @@ int __cifs_calc_signature(struct smb_rqst *rqst, struct kvec *iov = rqst->rq_iov; int n_vec = rqst->rq_nvec; - if (n_vec < 2 || iov[0].iov_len != 4) - return -EIO; + /* iov[0] is actual data and not the rfc1002 length for SMB2+ */ + if (server->vals->header_preamble_size == 0) { + rc = crypto_shash_update(shash, + iov[0].iov_base, iov[0].iov_len); + } else { + if (n_vec < 2 || iov[0].iov_len != 4) + return -EIO; + } for (i = 1; i < n_vec; i++) { if (iov[i].iov_len == 0) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 1c60b4e64656..6a2e33fa3b3a 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2062,7 +2062,7 @@ 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; + (struct smb2_sync_hdr *)old_rq->rq_iov[0].iov_base; memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr)); tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM; @@ -2073,14 +2073,13 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len, } /* Assumes: - * rqst->rq_iov[0] is rfc1002 length - * rqst->rq_iov[1] is tranform header - * rqst->rq_iov[2+] data to be encrypted/decrypted + * rqst->rq_iov[0] is tranform header + * rqst->rq_iov[1+] 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; + unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1; unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; struct scatterlist *sg; unsigned int i; @@ -2091,10 +2090,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[1].iov_base + 20, assoc_data_len); - for (i = 1; i < rqst->rq_nvec - 1; i++) - sg_set_buf(&sg[i], rqst->rq_iov[i+1].iov_base, - rqst->rq_iov[i+1].iov_len); + sg_set_buf(&sg[0], rqst->rq_iov[0].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); for (j = 0; i < sg_len - 1; i++, j++) { unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz : rqst->rq_tailsz; @@ -2125,18 +2124,17 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key) return 1; } /* - * Encrypt or decrypt @rqst message. @rqst has the following format: - * 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] + * Encrypt or decrypt @rqst message. @rqst[0] has the following format: + * iov[0] - transform header (associate data), + * iov[1-N] - SMB2 header and pages - data to encrypt. + * On success return encrypted data in iov[1-N] and pages, leave iov[0] * 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[1].iov_base; + (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base; unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; int rc = 0; struct scatterlist *sg; @@ -2149,7 +2147,6 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) struct crypto_aead *tfm; unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize); - /* Fixme compounding: get rid of iov[0] */ rc = smb2_get_enc_key(server, tr_hdr->SessionId, enc, key); if (rc) { cifs_dbg(VFS, "%s: Could not get %scryption key\n", __func__, @@ -2225,9 +2222,6 @@ 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) @@ -2236,7 +2230,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); + unsigned int orig_len = 0; int i; int rc = -ENOMEM; @@ -2249,24 +2243,23 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, new_rq->rq_pagesz = old_rq->rq_pagesz; new_rq->rq_tailsz = old_rq->rq_tailsz; + for (i = 0; i < old_rq->rq_nvec; i++) + orig_len += old_rq->rq_iov[i].iov_len; + for (i = 0; i < npages; i++) { pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); if (!pages[i]) goto err_free_pages; } - /* 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[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; + /* copy all iovs from the old */ + memcpy(&iov[1], &old_rq->rq_iov[0], + sizeof(struct kvec) * old_rq->rq_nvec); new_rq->rq_iov = iov; new_rq->rq_nvec = old_rq->rq_nvec + 1; @@ -2277,12 +2270,8 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, /* 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)); + new_rq->rq_iov[0].iov_base = tr_hdr; + new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr); /* copy pages form the old */ for (i = 0; i < npages; i++) { @@ -2322,7 +2311,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[1].iov_base); + kfree(rqst->rq_iov[0].iov_base); kfree(rqst->rq_iov); } @@ -2339,19 +2328,17 @@ 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[3]; + struct kvec iov[2]; struct smb_rqst rqst = {NULL}; int rc; - 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; + 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; rqst.rq_iov = iov; - rqst.rq_nvec = 3; + rqst.rq_nvec = 2; rqst.rq_pages = pages; rqst.rq_npages = npages; rqst.rq_pagesz = PAGE_SIZE; @@ -2363,7 +2350,7 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf, if (rc) return rc; - memmove(buf, iov[2].iov_base, buf_data_size); + memmove(buf, iov[1].iov_base, buf_data_size); server->total_read = buf_data_size + page_data_size; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index ad178150fbf3..a1a25b46cc2e 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2344,11 +2344,10 @@ SMB2_echo(struct TCP_Server_Info *server) { struct smb2_echo_req *req; int rc = 0; - struct kvec iov[2]; + struct kvec iov[1]; struct smb_rqst rqst = { .rq_iov = iov, - .rq_nvec = 2 }; + .rq_nvec = 1 }; unsigned int total_len; - __be32 rfc1002_marker; cifs_dbg(FYI, "In echo request\n"); @@ -2364,11 +2363,8 @@ SMB2_echo(struct TCP_Server_Info *server) req->sync_hdr.CreditRequest = cpu_to_le16(1); - iov[0].iov_len = 4; - rfc1002_marker = cpu_to_be32(total_len); - iov[0].iov_base = &rfc1002_marker; - iov[1].iov_len = total_len; - iov[1].iov_base = (char *)req; + iov[0].iov_len = total_len; + iov[0].iov_base = (char *)req; rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL, server, CIFS_ECHO_OP); @@ -2551,10 +2547,9 @@ smb2_async_readv(struct cifs_readdata *rdata) struct smb2_sync_hdr *shdr; struct cifs_io_parms io_parms; struct smb_rqst rqst = { .rq_iov = rdata->iov, - .rq_nvec = 2 }; + .rq_nvec = 1 }; struct TCP_Server_Info *server; unsigned int total_len; - __be32 req_len; cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", __func__, rdata->offset, rdata->bytes); @@ -2585,12 +2580,8 @@ smb2_async_readv(struct cifs_readdata *rdata) if (encryption_required(io_parms.tcon)) flags |= CIFS_TRANSFORM_REQ; - req_len = cpu_to_be32(total_len); - - rdata->iov[0].iov_base = &req_len; - rdata->iov[0].iov_len = sizeof(__be32); - rdata->iov[1].iov_base = buf; - rdata->iov[1].iov_len = total_len; + rdata->iov[0].iov_base = buf; + rdata->iov[0].iov_len = total_len; shdr = (struct smb2_sync_hdr *)buf; @@ -2741,10 +2732,9 @@ smb2_async_writev(struct cifs_writedata *wdata, struct smb2_sync_hdr *shdr; struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); struct TCP_Server_Info *server = tcon->ses->server; - struct kvec iov[2]; + struct kvec iov[1]; struct smb_rqst rqst = { }; unsigned int total_len; - __be32 rfc1002_marker; rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len); if (rc) { @@ -2775,12 +2765,8 @@ smb2_async_writev(struct cifs_writedata *wdata, offsetof(struct smb2_write_req, Buffer)); req->RemainingBytes = 0; - /* 4 for rfc1002 length field and 1 for Buffer */ - iov[0].iov_len = 4; - rfc1002_marker = cpu_to_be32(total_len - 1 + wdata->bytes); - iov[0].iov_base = &rfc1002_marker; - iov[1].iov_len = total_len - 1; - iov[1].iov_base = (char *)req; + iov[0].iov_len = total_len - 1; + iov[0].iov_base = (char *)req; rqst.rq_iov = iov; rqst.rq_nvec = 2; diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index cf37c6651bf6..dbd257faf01b 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -186,7 +186,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; unsigned char *sigptr = smb2_signature; struct kvec *iov = rqst->rq_iov; - struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base; + struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; struct cifs_ses *ses; ses = smb2_find_smb_ses(server, shdr->SessionId); @@ -427,7 +427,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) unsigned char smb3_signature[SMB2_CMACAES_SIZE]; unsigned char *sigptr = smb3_signature; struct kvec *iov = rqst->rq_iov; - struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base; + struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; struct cifs_ses *ses; ses = smb2_find_smb_ses(server, shdr->SessionId); @@ -473,7 +473,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) { int rc = 0; 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->Flags & SMB2_FLAGS_SIGNED) || server->tcpStatus == CifsNeedNegotiate) @@ -495,7 +495,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) || @@ -620,14 +620,12 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, bool log_error) { unsigned int len = get_rfc1002_length(mid->resp_buf); - 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 = NULL; - iov[0].iov_len = 4; - iov[1].iov_base = (char *)mid->resp_buf; - iov[1].iov_len = server->total_size; + iov[0].iov_base = (char *)mid->resp_buf; + iov[0].iov_len = server->total_size; dump_smb(mid->resp_buf, min_t(u32, 80, len)); /* convert the length into a more usable form */ @@ -648,7 +646,7 @@ smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst) { int rc; 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; struct mid_q_entry *mid; smb2_seq_num_into_buf(ses->server, shdr); @@ -669,7 +667,7 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) { int rc; 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; struct mid_q_entry *mid; smb2_seq_num_into_buf(server, shdr); diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 5cecf67af8f1..d6f26fc3e6f5 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -225,37 +225,45 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) int rc; struct kvec *iov = rqst->rq_iov; int n_vec = rqst->rq_nvec; - unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base); - unsigned long send_length; + unsigned int send_length; unsigned int i; size_t total_len = 0, sent, size; struct socket *ssocket = server->ssocket; struct msghdr smb_msg; int val = 1; + __be32 rfc1002_marker; if (ssocket == NULL) return -ENOTSOCK; - /* sanity check send length */ send_length = rqst_len(rqst); - if (send_length != smb_buf_length + 4) { - WARN(1, "Send length mismatch(send_length=%lu smb_buf_length=%u)\n", - send_length, smb_buf_length); - return -EIO; - } - - if (n_vec < 2) - return -EIO; - - cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length); - dump_smb(iov[0].iov_base, iov[0].iov_len); - dump_smb(iov[1].iov_base, iov[1].iov_len); + rfc1002_marker = cpu_to_be32(send_length); /* cork the socket */ kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, (char *)&val, sizeof(val)); size = 0; + /* Generate a rfc1002 marker for SMB2+ */ + if (server->vals->header_preamble_size == 0) { + struct kvec hiov = { + .iov_base = &rfc1002_marker, + .iov_len = 4 + }; + iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, &hiov, + 1, 4); + rc = smb_send_kvec(server, &smb_msg, &sent); + if (rc < 0) + goto uncork; + + total_len += sent; + send_length += 4; + } + + cifs_dbg(FYI, "Sending smb: smb_len=%u\n", send_length); + dump_smb(iov[0].iov_base, iov[0].iov_len); + dump_smb(iov[1].iov_base, iov[1].iov_len); + for (i = 0; i < n_vec; i++) size += iov[i].iov_len; @@ -291,9 +299,9 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, (char *)&val, sizeof(val)); - if ((total_len > 0) && (total_len != smb_buf_length + 4)) { + if ((total_len > 0) && (total_len != send_length)) { cifs_dbg(FYI, "partial send (wanted=%u sent=%zu): terminating session\n", - smb_buf_length + 4, total_len); + send_length, total_len); /* * If we have only sent part of an SMB then the next SMB could * be taken as the remainder of this one. We need to kill the @@ -713,7 +721,6 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, * to the same server. We may make this configurable later or * use ses->maxReq. */ - rc = wait_for_free_request(ses->server, timeout, optype); if (rc) return rc; @@ -844,39 +851,13 @@ smb2_send_recv(const unsigned int xid, struct cifs_ses *ses, const int flags, struct kvec *resp_iov) { struct smb_rqst rqst; - struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov; int rc; - int i; - __u32 count; - __be32 rfc1002_marker; - - if (n_vec + 1 > CIFS_MAX_IOV_SIZE) { - new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1), - GFP_KERNEL); - if (!new_iov) - return -ENOMEM; - } else - new_iov = s_iov; - - /* 1st iov is an RFC1002 Session Message length */ - memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec)); - - count = 0; - for (i = 1; i < n_vec + 1; i++) - count += new_iov[i].iov_len; - - rfc1002_marker = cpu_to_be32(count); - - new_iov[0].iov_base = &rfc1002_marker; - new_iov[0].iov_len = 4; memset(&rqst, 0, sizeof(struct smb_rqst)); - rqst.rq_iov = new_iov; - rqst.rq_nvec = n_vec + 1; + rqst.rq_iov = iov; + rqst.rq_nvec = n_vec; rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov); - if (n_vec + 1 > CIFS_MAX_IOV_SIZE) - kfree(new_iov); return rc; } From patchwork Tue Feb 13 04:42:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872594 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVK26sp3z9sBZ for ; Tue, 13 Feb 2018 15:43:02 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933423AbeBMEnC (ORCPT ); Mon, 12 Feb 2018 23:43:02 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:42316 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933417AbeBMEnB (ORCPT ); Mon, 12 Feb 2018 23:43:01 -0500 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8290CE4486; Tue, 13 Feb 2018 04:43:01 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id 38DD42024CA1; Tue, 13 Feb 2018 04:42:58 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 04/14] cifs: remove smb2_send_recv() Date: Tue, 13 Feb 2018 15:42:24 +1100 Message-Id: <20180213044234.18364-5-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 13 Feb 2018 04:43:01 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 13 Feb 2018 04:43:01 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Now that we have the plumbing to pass request without an rfc1002 header all the way down to the point we write to the socket we no longer need the smb2_send_recv() function. Signed-off-by: Ronnie Sahlberg --- fs/cifs/cifsproto.h | 4 -- fs/cifs/smb2pdu.c | 137 ++++++++++++++++++++++++++++++++++++++++++++-------- fs/cifs/transport.c | 17 ------- 3 files changed, 116 insertions(+), 42 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 93d565186698..4143c9dec463 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -106,10 +106,6 @@ extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, struct kvec *, int /* nvec to send */, int * /* type of buf returned */, const int flags, struct kvec * /* resp vec */); -extern int smb2_send_recv(const unsigned int xid, struct cifs_ses *pses, - struct kvec *pkvec, int nvec_to_send, - int *pbuftype, const int flags, - struct kvec *presp); extern int SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *ptcon, struct smb_hdr *in_buf , diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index a1a25b46cc2e..ac6b1d8d0c88 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -428,6 +428,7 @@ static void assemble_neg_contexts(struct smb2_negotiate_req *req, int SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) { + struct smb_rqst rqst; struct smb2_negotiate_req *req; struct smb2_negotiate_rsp *rsp; struct kvec iov[1]; @@ -495,7 +496,11 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) iov[0].iov_base = (char *)req; iov[0].iov_len = total_len; - rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(req); rsp = (struct smb2_negotiate_rsp *)rsp_iov.iov_base; /* @@ -818,6 +823,7 @@ static int SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data) { int rc; + struct smb_rqst rqst; struct smb2_sess_setup_req *req = sess_data->iov[0].iov_base; struct kvec rsp_iov = { NULL, 0 }; @@ -826,10 +832,13 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data) cpu_to_le16(sizeof(struct smb2_sess_setup_req) - 1 /* pad */); req->SecurityBufferLength = cpu_to_le16(sess_data->iov[1].iov_len); - /* BB add code to build os and lm fields */ + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = sess_data->iov; + rqst.rq_nvec = 2; - rc = smb2_send_recv(sess_data->xid, sess_data->ses, - sess_data->iov, 2, + /* BB add code to build os and lm fields */ + rc = cifs_send_recv(sess_data->xid, sess_data->ses, + &rqst, &sess_data->buf0_type, CIFS_LOG_ERROR | CIFS_NEG_OP, &rsp_iov); cifs_small_buf_release(sess_data->iov[0].iov_base); @@ -1158,6 +1167,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) { + struct smb_rqst rqst; struct smb2_logoff_req *req; /* response is also trivial struct */ int rc = 0; struct TCP_Server_Info *server; @@ -1195,7 +1205,11 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) iov[0].iov_base = (char *)req; iov[0].iov_len = total_len; - rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov); cifs_small_buf_release(req); /* * No tcon so can't do @@ -1225,6 +1239,7 @@ int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, struct cifs_tcon *tcon, const struct nls_table *cp) { + struct smb_rqst rqst; struct smb2_tree_connect_req *req; struct smb2_tree_connect_rsp *rsp = NULL; struct kvec iov[2]; @@ -1285,7 +1300,11 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, iov[1].iov_base = unc_path; iov[1].iov_len = unc_path_len; - rc = smb2_send_recv(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 2; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(req); rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base; @@ -1354,6 +1373,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) { + struct smb_rqst rqst; struct smb2_tree_disconnect_req *req; /* response is trivial */ int rc = 0; struct cifs_ses *ses = tcon->ses; @@ -1384,7 +1404,11 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) iov[0].iov_base = (char *)req; iov[0].iov_len = total_len; - rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov); cifs_small_buf_release(req); if (rc) cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE); @@ -1681,6 +1705,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, __u8 *oplock, struct smb2_file_all_info *buf, struct kvec *err_iov) { + struct smb_rqst rqst; struct smb2_create_req *req; struct smb2_create_rsp *rsp; struct TCP_Server_Info *server; @@ -1808,7 +1833,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, dhc_buf = iov[n_iov-1].iov_base; } - rc = smb2_send_recv(xid, ses, iov, n_iov, &resp_buftype, flags, + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = n_iov; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(req); rsp = (struct smb2_create_rsp *)rsp_iov.iov_base; @@ -1855,6 +1884,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, char *in_data, u32 indatalen, char **out_data, u32 *plen /* returned data len */) { + struct smb_rqst rqst; struct smb2_ioctl_req *req; struct smb2_ioctl_rsp *rsp; struct cifs_ses *ses; @@ -1955,7 +1985,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO) req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED; - rc = smb2_send_recv(xid, ses, iov, n_iov, &resp_buftype, flags, + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = n_iov; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(req); rsp = (struct smb2_ioctl_rsp *)rsp_iov.iov_base; @@ -2037,6 +2071,7 @@ int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid) { + struct smb_rqst rqst; struct smb2_close_req *req; struct smb2_close_rsp *rsp; struct cifs_ses *ses = tcon->ses; @@ -2065,7 +2100,11 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, iov[0].iov_base = (char *)req; iov[0].iov_len = total_len; - rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(req); rsp = (struct smb2_close_rsp *)rsp_iov.iov_base; @@ -2142,6 +2181,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, u32 additional_info, size_t output_len, size_t min_len, void **data, u32 *dlen) { + struct smb_rqst rqst; struct smb2_query_info_req *req; struct smb2_query_info_rsp *rsp = NULL; struct kvec iov[2]; @@ -2182,7 +2222,11 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, /* 1 for Buffer */ iov[0].iov_len = total_len - 1; - rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(req); rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; @@ -2379,6 +2423,7 @@ int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid) { + struct smb_rqst rqst; struct smb2_flush_req *req; struct cifs_ses *ses = tcon->ses; struct kvec iov[1]; @@ -2406,7 +2451,11 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, iov[0].iov_base = (char *)req; iov[0].iov_len = total_len; - rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(req); if (rc != 0) @@ -2614,6 +2663,7 @@ int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes, char **buf, int *buf_type) { + struct smb_rqst rqst; int resp_buftype, rc = -EACCES; struct smb2_read_plain_req *req = NULL; struct smb2_read_rsp *rsp = NULL; @@ -2634,7 +2684,11 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, iov[0].iov_base = (char *)req; iov[0].iov_len = total_len; - rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(req); rsp = (struct smb2_read_rsp *)rsp_iov.iov_base; @@ -2816,6 +2870,7 @@ int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes, struct kvec *iov, int n_vec) { + struct smb_rqst rqst; int rc = 0; struct smb2_write_req *req = NULL; struct smb2_write_rsp *rsp = NULL; @@ -2857,7 +2912,11 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, /* 1 for Buffer */ iov[0].iov_len = total_len - 1; - rc = smb2_send_recv(xid, io_parms->tcon->ses, iov, n_vec + 1, + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = n_vec + 1; + + rc = cifs_send_recv(xid, io_parms->tcon->ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(req); rsp = (struct smb2_write_rsp *)rsp_iov.iov_base; @@ -2920,6 +2979,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, int index, struct cifs_search_info *srch_inf) { + struct smb_rqst rqst; struct smb2_query_directory_req *req; struct smb2_query_directory_rsp *rsp = NULL; struct kvec iov[2]; @@ -2992,7 +3052,11 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, iov[1].iov_base = (char *)(req->Buffer); iov[1].iov_len = len; - rc = smb2_send_recv(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 2; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(req); rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base; @@ -3051,6 +3115,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, u8 info_type, u32 additional_info, unsigned int num, void **data, unsigned int *size) { + struct smb_rqst rqst; struct smb2_set_info_req *req; struct smb2_set_info_rsp *rsp = NULL; struct kvec *iov; @@ -3106,7 +3171,11 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, iov[i].iov_len = size[i]; } - rc = smb2_send_recv(xid, ses, iov, num, &resp_buftype, flags, + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = num; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(req); rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base; @@ -3258,6 +3327,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, const u64 persistent_fid, const u64 volatile_fid, __u8 oplock_level) { + struct smb_rqst rqst; int rc; struct smb2_oplock_break *req = NULL; struct cifs_ses *ses = tcon->ses; @@ -3286,7 +3356,11 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, iov[0].iov_base = (char *)req; iov[0].iov_len = total_len; - rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov); cifs_small_buf_release(req); if (rc) { @@ -3346,6 +3420,7 @@ int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata) { + struct smb_rqst rqst; struct smb2_query_info_rsp *rsp = NULL; struct kvec iov; struct kvec rsp_iov; @@ -3364,7 +3439,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, if (encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; - rc = smb2_send_recv(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = &iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(iov.iov_base); if (rc) { cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE); @@ -3389,6 +3468,7 @@ int SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, int level) { + struct smb_rqst rqst; struct smb2_query_info_rsp *rsp = NULL; struct kvec iov; struct kvec rsp_iov; @@ -3420,7 +3500,11 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, if (encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; - rc = smb2_send_recv(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = &iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); cifs_small_buf_release(iov.iov_base); if (rc) { cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE); @@ -3459,6 +3543,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, const __u64 persist_fid, const __u64 volatile_fid, const __u32 pid, const __u32 num_lock, struct smb2_lock_element *buf) { + struct smb_rqst rqst; int rc = 0; struct smb2_lock_req *req = NULL; struct kvec iov[2]; @@ -3491,7 +3576,12 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, iov[1].iov_len = count; cifs_stats_inc(&tcon->stats.cifs_stats.num_locks); - rc = smb2_send_recv(xid, tcon->ses, iov, 2, &resp_buf_type, flags, + + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 2; + + rc = cifs_send_recv(xid, tcon->ses, &rqst, &resp_buf_type, flags, &rsp_iov); cifs_small_buf_release(req); if (rc) { @@ -3523,6 +3613,7 @@ int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, __u8 *lease_key, const __le32 lease_state) { + struct smb_rqst rqst; int rc; struct smb2_lease_ack *req = NULL; struct cifs_ses *ses = tcon->ses; @@ -3553,7 +3644,11 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, iov[0].iov_base = (char *)req; iov[0].iov_len = total_len; - rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov); + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov); cifs_small_buf_release(req); if (rc) { diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index d6f26fc3e6f5..35ef3f7e7ab0 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -844,23 +844,6 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, return rc; } -/* Like SendReceive2 but iov[0] does not contain an rfc1002 header */ -int -smb2_send_recv(const unsigned int xid, struct cifs_ses *ses, - struct kvec *iov, int n_vec, int *resp_buf_type /* ret */, - const int flags, struct kvec *resp_iov) -{ - struct smb_rqst rqst; - int rc; - - memset(&rqst, 0, sizeof(struct smb_rqst)); - rqst.rq_iov = iov; - rqst.rq_nvec = n_vec; - - rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov); - return rc; -} - int SendReceive(const unsigned int xid, struct cifs_ses *ses, struct smb_hdr *in_buf, struct smb_hdr *out_buf, From patchwork Tue Feb 13 04:42:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872605 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVL30J72z9sBZ for ; Tue, 13 Feb 2018 15:43:55 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933426AbeBMEny (ORCPT ); Mon, 12 Feb 2018 23:43:54 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:41270 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933378AbeBMEny (ORCPT ); Mon, 12 Feb 2018 23:43:54 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D9A9B7CBDB; Tue, 13 Feb 2018 04:43:53 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id A754E2166BAE; Tue, 13 Feb 2018 04:43:52 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 05/14] cifs: update __smb_send_rqst() to take an array of requests Date: Tue, 13 Feb 2018 15:42:25 +1100 Message-Id: <20180213044234.18364-6-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Tue, 13 Feb 2018 04:43:53 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Tue, 13 Feb 2018 04:43:53 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Also create a new method set_next_header() which we will start using in the next few patches. Signed-off-by: Ronnie Sahlberg --- fs/cifs/cifsglob.h | 1 + fs/cifs/smb2ops.c | 15 ++++++++++ fs/cifs/smb2proto.h | 1 + fs/cifs/transport.c | 84 +++++++++++++++++++++++++++++------------------------ 4 files changed, 63 insertions(+), 38 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 18a961d32e0c..51d0d29dceed 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -450,6 +450,7 @@ struct smb_version_operations { enum securityEnum (*select_sectype)(struct TCP_Server_Info *, enum securityEnum); int (*next_header)(char *); + void (*set_next_header)(char *, int); }; struct smb_version_values { diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 6a2e33fa3b3a..be1cb6aaa19c 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2717,6 +2717,17 @@ smb2_next_header(char *buf) return le32_to_cpu(hdr->NextCommand); } +static void +smb2_set_next_header(char *buf, int offset) +{ + struct smb2_sync_hdr *hdr = (struct smb2_sync_hdr *)buf; + + if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) + return; + + hdr->NextCommand = cpu_to_le32(offset); +} + struct smb_version_operations smb20_operations = { .compare_fids = smb2_compare_fids, .setup_request = smb2_setup_request, @@ -2809,6 +2820,7 @@ struct smb_version_operations smb20_operations = { .set_acl = set_smb2_acl, #endif /* CIFS_ACL */ .next_header = smb2_next_header, + .set_next_header = smb2_set_next_header, }; struct smb_version_operations smb21_operations = { @@ -2904,6 +2916,7 @@ struct smb_version_operations smb21_operations = { .set_acl = set_smb2_acl, #endif /* CIFS_ACL */ .next_header = smb2_next_header, + .set_next_header = smb2_set_next_header, }; struct smb_version_operations smb30_operations = { @@ -3009,6 +3022,7 @@ struct smb_version_operations smb30_operations = { .set_acl = set_smb2_acl, #endif /* CIFS_ACL */ .next_header = smb2_next_header, + .set_next_header = smb2_set_next_header, }; #ifdef CONFIG_CIFS_SMB311 @@ -3110,6 +3124,7 @@ struct smb_version_operations smb311_operations = { .set_EA = smb2_set_ea, #endif /* CIFS_XATTR */ .next_header = smb2_next_header, + .set_next_header = smb2_set_next_header, }; #endif /* CIFS_SMB311 */ diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 089a6ef936b8..d35e6bfa079d 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -204,4 +204,5 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, enum securityEnum); +extern int smb3_encryption_required(const struct cifs_tcon *tcon); #endif /* _SMB2PROTO_H */ diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 35ef3f7e7ab0..b2af2341f6b8 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -200,7 +200,7 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, } static unsigned long -rqst_len(struct smb_rqst *rqst) +smb2_rqst_len(struct smb_rqst *rqst) { unsigned int i; struct kvec *iov = rqst->rq_iov; @@ -220,13 +220,14 @@ rqst_len(struct smb_rqst *rqst) } static int -__smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) +__smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, + struct smb_rqst *rqst) { - int rc; - struct kvec *iov = rqst->rq_iov; - int n_vec = rqst->rq_nvec; - unsigned int send_length; - unsigned int i; + int rc = 0; + struct kvec *iov; + int n_vec; + unsigned int send_length = 0; + unsigned int i, j; size_t total_len = 0, sent, size; struct socket *ssocket = server->ssocket; struct msghdr smb_msg; @@ -236,14 +237,14 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) if (ssocket == NULL) return -ENOTSOCK; - send_length = rqst_len(rqst); - rfc1002_marker = cpu_to_be32(send_length); - /* cork the socket */ kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, (char *)&val, sizeof(val)); - size = 0; + for (j = 0; j < num_rqst; j++) + send_length += smb2_rqst_len(&rqst[j]); + rfc1002_marker = cpu_to_be32(send_length); + /* Generate a rfc1002 marker for SMB2+ */ if (server->vals->header_preamble_size == 0) { struct kvec hiov = { @@ -260,37 +261,44 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) send_length += 4; } - cifs_dbg(FYI, "Sending smb: smb_len=%u\n", send_length); - dump_smb(iov[0].iov_base, iov[0].iov_len); - dump_smb(iov[1].iov_base, iov[1].iov_len); + for (j = 0; j < num_rqst; j++) { + iov = rqst[j].rq_iov; + n_vec = rqst[j].rq_nvec; - for (i = 0; i < n_vec; i++) - size += iov[i].iov_len; + cifs_dbg(FYI, "Sending smb: smb_len=%u\n", send_length); + dump_smb(iov[0].iov_base, iov[0].iov_len); + dump_smb(iov[1].iov_base, iov[1].iov_len); - iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, iov, n_vec, size); + size = 0; + for (i = 0; i < n_vec; i++) + size += iov[i].iov_len; + + iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, + iov, n_vec, size); - rc = smb_send_kvec(server, &smb_msg, &sent); - if (rc < 0) - goto uncork; - - total_len += sent; - - /* now walk the page array and send each page in it */ - for (i = 0; i < rqst->rq_npages; i++) { - size_t len = i == rqst->rq_npages - 1 - ? rqst->rq_tailsz - : rqst->rq_pagesz; - struct bio_vec bvec = { - .bv_page = rqst->rq_pages[i], - .bv_len = len - }; - iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC, - &bvec, 1, len); rc = smb_send_kvec(server, &smb_msg, &sent); if (rc < 0) - break; + goto uncork; total_len += sent; + + /* now walk the page array and send each page in it */ + for (i = 0; i < rqst[j].rq_npages; i++) { + size_t len = i == rqst[j].rq_npages - 1 + ? rqst[j].rq_tailsz + : rqst[j].rq_pagesz; + struct bio_vec bvec = { + .bv_page = rqst[j].rq_pages[i], + .bv_len = len + }; + iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC, + &bvec, 1, len); + rc = smb_send_kvec(server, &smb_msg, &sent); + if (rc < 0) + break; + + total_len += sent; + } } uncork: @@ -326,7 +334,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags) int rc; if (!(flags & CIFS_TRANSFORM_REQ)) - return __smb_send_rqst(server, rqst); + return __smb_send_rqst(server, 1, rqst); if (!server->ops->init_transform_rq || !server->ops->free_transform_rq) { @@ -338,7 +346,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags) if (rc) return rc; - rc = __smb_send_rqst(server, &cur_rqst); + rc = __smb_send_rqst(server, 1, &cur_rqst); server->ops->free_transform_rq(&cur_rqst); return rc; } @@ -356,7 +364,7 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, iov[1].iov_base = (char *)smb_buffer + 4; iov[1].iov_len = smb_buf_length; - return __smb_send_rqst(server, &rqst); + return __smb_send_rqst(server, 1, &rqst); } static int From patchwork Tue Feb 13 04:42:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872597 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVKJ3mLPz9sBZ for ; Tue, 13 Feb 2018 15:43:16 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933417AbeBMEnQ (ORCPT ); Mon, 12 Feb 2018 23:43:16 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:42326 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933378AbeBMEnP (ORCPT ); Mon, 12 Feb 2018 23:43:15 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 38E1AE4486; Tue, 13 Feb 2018 04:43:15 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id 89A491006EA1; Tue, 13 Feb 2018 04:43:12 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 06/14] cifs: make smb_send_rqst() take an array of requests Date: Tue, 13 Feb 2018 15:42:26 +1100 Message-Id: <20180213044234.18364-7-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 13 Feb 2018 04:43:15 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 13 Feb 2018 04:43:15 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Update free_transform_rq to take an array of requests. Only the first request has a transform header which needs to be freed. Signed-off-by: Ronnie Sahlberg --- fs/cifs/cifsglob.h | 6 +++--- fs/cifs/smb2ops.c | 37 +++++++++++++++++++++---------------- fs/cifs/transport.c | 22 ++++++++++++++-------- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 51d0d29dceed..a5ffcaf4b144 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -440,10 +440,10 @@ struct smb_version_operations { long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t, loff_t); /* init transform request - used for encryption for now */ - int (*init_transform_rq)(struct TCP_Server_Info *, struct smb_rqst *, - struct smb_rqst *); + int (*init_transform_rq)(struct TCP_Server_Info *, int num_rqst, + struct smb_rqst *, struct smb_rqst *); /* free transform request */ - void (*free_transform_rq)(struct smb_rqst *); + void (*free_transform_rq)(int num_rqst, struct smb_rqst *); int (*is_transform_hdr)(void *buf); int (*receive_transform)(struct TCP_Server_Info *, struct mid_q_entry **); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index be1cb6aaa19c..23ff4cf3ac88 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2222,9 +2222,10 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) return rc; } +/* Encrypt all the requests but only add a transform header to the first */ static int -smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, - struct smb_rqst *old_rq) +smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, + struct smb_rqst *new_rq, struct smb_rqst *old_rq) { struct kvec *iov; struct page **pages; @@ -2234,9 +2235,13 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, int i; int rc = -ENOMEM; + tr_hdr = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL); + if (!tr_hdr) + return rc; + pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); if (!pages) - return rc; + goto err_free_tr_hdr; new_rq->rq_pages = pages; new_rq->rq_npages = old_rq->rq_npages; @@ -2264,10 +2269,6 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, new_rq->rq_iov = iov; 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 2nd iov with a transform header */ fill_transform_hdr(tr_hdr, orig_len, old_rq); new_rq->rq_iov[0].iov_base = tr_hdr; @@ -2287,32 +2288,36 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, rc = crypt_message(server, new_rq, 1); cifs_dbg(FYI, "encrypt message returned %d", rc); if (rc) - goto err_free_tr_hdr; + goto err_free_iov; return rc; -err_free_tr_hdr: - kfree(tr_hdr); err_free_iov: kfree(iov); err_free_pages: for (i = i - 1; i >= 0; i--) put_page(pages[i]); kfree(pages); +err_free_tr_hdr: + kfree(tr_hdr); return rc; } +/* Only the first request has a transform header */ static void -smb3_free_transform_rq(struct smb_rqst *rqst) +smb3_free_transform_rq(int num_rqst, struct smb_rqst *rqst) { - int i = rqst->rq_npages - 1; + int i, j; - for (; i >= 0; i--) - put_page(rqst->rq_pages[i]); - kfree(rqst->rq_pages); /* free transform header */ kfree(rqst->rq_iov[0].iov_base); - kfree(rqst->rq_iov); + + for (i = 0; i < num_rqst; i++) { + for (j = rqst[i].rq_npages - 1; j >= 0; j--) + put_page(rqst[i].rq_pages[j]); + kfree(rqst[i].rq_pages); + kfree(rqst[i].rq_iov); + } } static int diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index b2af2341f6b8..6f3733380e41 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -327,14 +327,20 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, return rc; } +#define MAX_COMPOUND 5 + static int -smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags) +smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, + struct smb_rqst *rqst, int flags) { - struct smb_rqst cur_rqst; + struct smb_rqst cur_rqst[MAX_COMPOUND]; int rc; + if (num_rqst > MAX_COMPOUND) + return -ENOMEM; + if (!(flags & CIFS_TRANSFORM_REQ)) - return __smb_send_rqst(server, 1, rqst); + return __smb_send_rqst(server, num_rqst, rqst); if (!server->ops->init_transform_rq || !server->ops->free_transform_rq) { @@ -342,12 +348,12 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags) return -EIO; } - rc = server->ops->init_transform_rq(server, &cur_rqst, rqst); + rc = server->ops->init_transform_rq(server, num_rqst, cur_rqst, rqst); if (rc) return rc; - rc = __smb_send_rqst(server, 1, &cur_rqst); - server->ops->free_transform_rq(&cur_rqst); + rc = __smb_send_rqst(server, num_rqst, cur_rqst); + server->ops->free_transform_rq(num_rqst, cur_rqst); return rc; } @@ -561,7 +567,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, */ cifs_save_when_sent(mid); cifs_in_send_inc(server); - rc = smb_send_rqst(server, rqst, flags); + rc = smb_send_rqst(server, 1, rqst, flags); cifs_in_send_dec(server); if (rc < 0) { @@ -751,7 +757,7 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, midQ->mid_state = MID_REQUEST_SUBMITTED; cifs_in_send_inc(ses->server); - rc = smb_send_rqst(ses->server, rqst, flags); + rc = smb_send_rqst(ses->server, 1, rqst, flags); cifs_in_send_dec(ses->server); cifs_save_when_sent(midQ); From patchwork Tue Feb 13 04:42:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872598 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVKP5H1rz9sBZ for ; Tue, 13 Feb 2018 15:43:21 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933426AbeBMEnV (ORCPT ); Mon, 12 Feb 2018 23:43:21 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45392 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933378AbeBMEnU (ORCPT ); Mon, 12 Feb 2018 23:43:20 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 762D040FB62D; Tue, 13 Feb 2018 04:43:20 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id CBDB42166BAE; Tue, 13 Feb 2018 04:43:18 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 07/14] cifs: update init_sg and crypt_message to take an array of rqst Date: Tue, 13 Feb 2018 15:42:27 +1100 Message-Id: <20180213044234.18364-8-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 13 Feb 2018 04:43:20 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 13 Feb 2018 04:43:20 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org This is used for SMB3 encryption and compounded requests. The first rqst begins with a smb3 transform header as the first iov. Signed-off-by: Ronnie Sahlberg --- fs/cifs/smb2ops.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 23ff4cf3ac88..dd49354a35af 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2077,29 +2077,42 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len, * rqst->rq_iov[1+] data to be encrypted/decrypted */ static struct scatterlist * -init_sg(struct smb_rqst *rqst, u8 *sign) +init_sg(int num_rqst, 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) - 20; struct scatterlist *sg; unsigned int i; unsigned int j; + unsigned int idx = 0; sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL); if (!sg) return NULL; sg_init_table(sg, sg_len); - sg_set_buf(&sg[0], rqst->rq_iov[0].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); - for (j = 0; i < sg_len - 1; i++, j++) { - unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz - : rqst->rq_tailsz; - sg_set_page(&sg[i], rqst->rq_pages[j], len, 0); - } - sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE); + for (i = 0; i < num_rqst; i++) { + /* the first rqst has a transform header where the first 20 + * bytes are not part of the encrypted blob + */ + if (i == 0) + sg_set_buf(&sg[idx++], rqst[i].rq_iov[i].iov_base + 20, + assoc_data_len); + else + sg_set_buf(&sg[idx++], rqst[i].rq_iov[i].iov_base, + rqst[i].rq_iov[0].iov_len); + + for (j = 1; j < rqst[i].rq_nvec; j++) + sg_set_buf(&sg[idx++], rqst[i].rq_iov[j].iov_base, + rqst[i].rq_iov[j].iov_len); + + for (j = 0; j < rqst[i].rq_npages; j++) { + unsigned int len = (j < rqst[i].rq_npages - 1) ? + rqst[i].rq_pagesz : rqst[i].rq_tailsz; + sg_set_page(&sg[idx++], rqst[i].rq_pages[j], len, 0); + } + } + sg_set_buf(&sg[idx], sign, SMB2_SIGNATURE_SIZE); return sg; } @@ -2131,7 +2144,8 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key) * untouched. */ static int -crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) +crypt_message(struct TCP_Server_Info *server, int num_rqst, + struct smb_rqst *rqst, int enc) { struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base; @@ -2185,7 +2199,7 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) crypt_len += SMB2_SIGNATURE_SIZE; } - sg = init_sg(rqst, sign); + sg = init_sg(num_rqst, rqst, sign); if (!sg) { cifs_dbg(VFS, "%s: Failed to init sg", __func__); rc = -ENOMEM; @@ -2269,7 +2283,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, new_rq->rq_iov = iov; new_rq->rq_nvec = old_rq->rq_nvec + 1; - /* fill the 2nd iov with a transform header */ + /* fill the 1st iov with a transform header */ fill_transform_hdr(tr_hdr, orig_len, old_rq); new_rq->rq_iov[0].iov_base = tr_hdr; new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr); @@ -2285,7 +2299,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, kunmap(old_rq->rq_pages[i]); } - rc = crypt_message(server, new_rq, 1); + rc = crypt_message(server, num_rqst, new_rq, 1); cifs_dbg(FYI, "encrypt message returned %d", rc); if (rc) goto err_free_iov; @@ -2349,7 +2363,7 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf, rqst.rq_pagesz = PAGE_SIZE; rqst.rq_tailsz = (page_data_size % PAGE_SIZE) ? : PAGE_SIZE; - rc = crypt_message(server, &rqst, 0); + rc = crypt_message(server, 1, &rqst, 0); cifs_dbg(FYI, "decrypt message returned %d\n", rc); if (rc) From patchwork Tue Feb 13 04:42:28 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872599 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVKV3Jr2z9sBZ for ; Tue, 13 Feb 2018 15:43:26 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933429AbeBMEn0 (ORCPT ); Mon, 12 Feb 2018 23:43:26 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:41264 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933378AbeBMEnZ (ORCPT ); Mon, 12 Feb 2018 23:43:25 -0500 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 439C47D840; Tue, 13 Feb 2018 04:43:25 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id C62DF2024CA1; Tue, 13 Feb 2018 04:43:23 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 08/14] cifs: update smb3_init_transform_rq to take an array of requests Date: Tue, 13 Feb 2018 15:42:28 +1100 Message-Id: <20180213044234.18364-9-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Tue, 13 Feb 2018 04:43:25 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Tue, 13 Feb 2018 04:43:25 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org The first request will get pre-pended with a smb3 transform header. Signed-off-by: Ronnie Sahlberg --- fs/cifs/smb2ops.c | 119 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 52 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index dd49354a35af..80462bb3fd03 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2236,68 +2236,85 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst, return rc; } +static void +smb3_free_transform_rq_one(struct smb_rqst *rqst) +{ + int i; + + for (i = rqst->rq_npages - 1; i >= 0; i--) + put_page(rqst->rq_pages[i]); + kfree(rqst->rq_pages); + kfree(rqst->rq_iov); +} + /* Encrypt all the requests but only add a transform header to the first */ static int smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, struct smb_rqst *new_rq, struct smb_rqst *old_rq) { - struct kvec *iov; - struct page **pages; + struct kvec *iov = NULL; + struct page **pages = NULL; struct smb2_transform_hdr *tr_hdr; - unsigned int npages = old_rq->rq_npages; + unsigned int npages; unsigned int orig_len = 0; - int i; + int i, j = 0; int rc = -ENOMEM; tr_hdr = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL); if (!tr_hdr) return rc; - pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); - if (!pages) - goto err_free_tr_hdr; - - new_rq->rq_pages = pages; - new_rq->rq_npages = old_rq->rq_npages; - new_rq->rq_pagesz = old_rq->rq_pagesz; - new_rq->rq_tailsz = old_rq->rq_tailsz; - - for (i = 0; i < old_rq->rq_nvec; i++) - orig_len += old_rq->rq_iov[i].iov_len; + for (i = 0; i < num_rqst; i++) { + for (j = 0; j < old_rq[i].rq_nvec; j++) + orig_len += old_rq[i].rq_iov[j].iov_len; + + npages = old_rq[i].rq_npages; + pages = kmalloc_array(npages, sizeof(struct page *), + GFP_KERNEL); + if (!pages) + goto err_free_tr_hdr; + + new_rq[i].rq_pages = pages; + new_rq[i].rq_npages = old_rq[i].rq_npages; + new_rq[i].rq_pagesz = old_rq[i].rq_pagesz; + new_rq[i].rq_tailsz = old_rq[i].rq_tailsz; + + for (j = 0; j < npages; j++) { + pages[j] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); + if (!pages[j]) + goto err_free_pages; + } - for (i = 0; i < npages; i++) { - pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); - if (!pages[i]) + /* Copy all iovs from the old. The first request has an extra + * iov to hold the transform header. + */ + iov = kmalloc_array(old_rq[i].rq_nvec + (i == 0), + sizeof(struct kvec), GFP_KERNEL); + if (!iov) goto err_free_pages; - } - - 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 */ - memcpy(&iov[1], &old_rq->rq_iov[0], - sizeof(struct kvec) * old_rq->rq_nvec); - - new_rq->rq_iov = iov; - new_rq->rq_nvec = old_rq->rq_nvec + 1; + memcpy(&iov[i == 0], &old_rq[i].rq_iov[0], + sizeof(struct kvec) * old_rq[i].rq_nvec); + + new_rq->rq_iov = iov; + new_rq->rq_nvec = old_rq[i].rq_nvec + (i == 0); + + /* copy pages form the old */ + for (j = 0; j < npages; j++) { + char *dst = kmap(new_rq[i].rq_pages[j]); + char *src = kmap(old_rq[i].rq_pages[j]); + unsigned int len = (j < npages - 1) ? + new_rq[i].rq_pagesz : new_rq[i].rq_tailsz; + memcpy(dst, src, len); + kunmap(new_rq[i].rq_pages[j]); + kunmap(old_rq[i].rq_pages[j]); + } + } /* fill the 1st iov with a transform header */ fill_transform_hdr(tr_hdr, orig_len, old_rq); - new_rq->rq_iov[0].iov_base = tr_hdr; - new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr); - - /* copy pages form the old */ - for (i = 0; i < npages; i++) { - char *dst = kmap(new_rq->rq_pages[i]); - char *src = kmap(old_rq->rq_pages[i]); - unsigned int len = (i < npages - 1) ? new_rq->rq_pagesz : - new_rq->rq_tailsz; - memcpy(dst, src, len); - kunmap(new_rq->rq_pages[i]); - kunmap(old_rq->rq_pages[i]); - } + new_rq[0].rq_iov[0].iov_base = tr_hdr; + new_rq[0].rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr); rc = crypt_message(server, num_rqst, new_rq, 1); cifs_dbg(FYI, "encrypt message returned %d", rc); @@ -2309,11 +2326,13 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, err_free_iov: kfree(iov); err_free_pages: - for (i = i - 1; i >= 0; i--) - put_page(pages[i]); + for (j = j - 1; j >= 0; j--) + put_page(pages[j]); kfree(pages); err_free_tr_hdr: kfree(tr_hdr); + while (--i >= 0) + smb3_free_transform_rq_one(&new_rq[i]); return rc; } @@ -2321,17 +2340,13 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, static void smb3_free_transform_rq(int num_rqst, struct smb_rqst *rqst) { - int i, j; + int i; /* free transform header */ kfree(rqst->rq_iov[0].iov_base); - for (i = 0; i < num_rqst; i++) { - for (j = rqst[i].rq_npages - 1; j >= 0; j--) - put_page(rqst[i].rq_pages[j]); - kfree(rqst[i].rq_pages); - kfree(rqst[i].rq_iov); - } + for (i = 0; i < num_rqst; i++) + smb3_free_transform_rq_one(&rqst[i]); } static int From patchwork Tue Feb 13 04:42:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872596 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVKD0BHGz9sBZ for ; Tue, 13 Feb 2018 15:43:12 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933428AbeBMEnL (ORCPT ); Mon, 12 Feb 2018 23:43:11 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:42320 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933378AbeBMEnL (ORCPT ); Mon, 12 Feb 2018 23:43:11 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B5375E4486; Tue, 13 Feb 2018 04:43:10 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id CFAD82166BAE; Tue, 13 Feb 2018 04:43:08 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 09/14] cifs: add compound_send_recv() Date: Tue, 13 Feb 2018 15:42:29 +1100 Message-Id: <20180213044234.18364-10-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 13 Feb 2018 04:43:10 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 13 Feb 2018 04:43:10 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Signed-off-by: Ronnie Sahlberg --- fs/cifs/cifsproto.h | 4 ++ fs/cifs/transport.c | 136 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 82 insertions(+), 58 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 4143c9dec463..c1d049aa6a75 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -87,6 +87,10 @@ extern int cifs_call_async(struct TCP_Server_Info *server, extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, struct smb_rqst *rqst, int *resp_buf_type, const int flags, struct kvec *resp_iov); +extern int compound_send_recv(const unsigned int xid, struct cifs_ses *ses, + const int flags, const int num_rqst, + struct smb_rqst *rqst, int *resp_buf_type, + struct kvec *resp_iov); extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *, struct smb_hdr * /* input */ , struct smb_hdr * /* out */ , diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 6f3733380e41..d810d4af33ad 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -707,20 +707,22 @@ cifs_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst) } int -cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, - struct smb_rqst *rqst, int *resp_buf_type, const int flags, - struct kvec *resp_iov) +compound_send_recv(const unsigned int xid, struct cifs_ses *ses, + const int flags, const int num_rqst, struct smb_rqst *rqst, + int *resp_buf_type, struct kvec *resp_iov) { - int rc = 0; + int i, rc = 0; int timeout, optype; - struct mid_q_entry *midQ; + struct mid_q_entry *midQ[MAX_COMPOUND]; unsigned int credits = 1; char *buf; + /* FIXME fix sequence_number and credits */ timeout = flags & CIFS_TIMEOUT_MASK; optype = flags & CIFS_OP_MASK; - *resp_buf_type = CIFS_NO_BUFFER; /* no response buf yet */ + for (i = 0; i < num_rqst; i++) + resp_buf_type[i] = CIFS_NO_BUFFER; /* no response buf yet */ if ((ses == NULL) || (ses->server == NULL)) { cifs_dbg(VFS, "Null session\n"); @@ -747,83 +749,101 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, mutex_lock(&ses->server->srv_mutex); - midQ = ses->server->ops->setup_request(ses, rqst); - if (IS_ERR(midQ)) { - mutex_unlock(&ses->server->srv_mutex); - /* Update # of requests on wire to server */ - add_credits(ses->server, 1, optype); - return PTR_ERR(midQ); + for (i = 0; i < num_rqst; i++) { + midQ[i] = ses->server->ops->setup_request(ses, &rqst[i]); + if (IS_ERR(midQ[i])) { + mutex_unlock(&ses->server->srv_mutex); + /* Update # of requests on wire to server */ + add_credits(ses->server, 1, optype); + return PTR_ERR(midQ[i]); + } + + midQ[i]->mid_state = MID_REQUEST_SUBMITTED; } - midQ->mid_state = MID_REQUEST_SUBMITTED; cifs_in_send_inc(ses->server); - rc = smb_send_rqst(ses->server, 1, rqst, flags); + rc = smb_send_rqst(ses->server, num_rqst, rqst, flags); cifs_in_send_dec(ses->server); - cifs_save_when_sent(midQ); - if (rc < 0) - ses->server->sequence_number -= 2; - mutex_unlock(&ses->server->srv_mutex); + for (i = 0; i < num_rqst; i++) { + cifs_save_when_sent(midQ[i]); - if (rc < 0) - goto out; + if (rc < 0) + ses->server->sequence_number -= 2; + mutex_unlock(&ses->server->srv_mutex); - if (timeout == CIFS_ASYNC_OP) - goto out; + if (rc < 0) + goto out; - rc = wait_for_response(ses->server, midQ); - if (rc != 0) { - cifs_dbg(FYI, "Cancelling wait for mid %llu\n", midQ->mid); - send_cancel(ses->server, rqst, midQ); - spin_lock(&GlobalMid_Lock); - if (midQ->mid_state == MID_REQUEST_SUBMITTED) { - midQ->mid_flags |= MID_WAIT_CANCELLED; - midQ->callback = DeleteMidQEntry; + if (timeout == CIFS_ASYNC_OP) + goto out; + + rc = wait_for_response(ses->server, midQ[i]); + if (rc != 0) { + cifs_dbg(FYI, "Cancelling wait for mid %llu\n", + midQ[i]->mid); + send_cancel(ses->server, &rqst[i], midQ[i]); + spin_lock(&GlobalMid_Lock); + if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) { + midQ[i]->mid_flags |= MID_WAIT_CANCELLED; + midQ[i]->callback = DeleteMidQEntry; + spin_unlock(&GlobalMid_Lock); + add_credits(ses->server, 1, optype); + return rc; + } spin_unlock(&GlobalMid_Lock); + } + + rc = cifs_sync_mid_result(midQ[i], ses->server); + if (rc != 0) { add_credits(ses->server, 1, optype); return rc; } - spin_unlock(&GlobalMid_Lock); - } - rc = cifs_sync_mid_result(midQ, ses->server); - if (rc != 0) { - add_credits(ses->server, 1, optype); - return rc; - } - - if (!midQ->resp_buf || midQ->mid_state != MID_RESPONSE_RECEIVED) { - rc = -EIO; - cifs_dbg(FYI, "Bad MID state?\n"); - goto out; - } + if (!midQ[i]->resp_buf || + midQ[i]->mid_state != MID_RESPONSE_RECEIVED) { + rc = -EIO; + cifs_dbg(FYI, "Bad MID state?\n"); + goto out; + } - buf = (char *)midQ->resp_buf; - resp_iov->iov_base = buf; - resp_iov->iov_len = ses->server->total_size + - ses->server->vals->header_preamble_size; + buf = (char *)midQ[i]->resp_buf; + resp_iov[i].iov_base = buf; + resp_iov[i].iov_len = ses->server->total_size + + ses->server->vals->header_preamble_size; - if (midQ->large_buf) - *resp_buf_type = CIFS_LARGE_BUFFER; - else - *resp_buf_type = CIFS_SMALL_BUFFER; + if (midQ[i]->large_buf) + resp_buf_type[i] = CIFS_LARGE_BUFFER; + else + resp_buf_type[i] = CIFS_SMALL_BUFFER; - credits = ses->server->ops->get_credits(midQ); + credits = ses->server->ops->get_credits(midQ[i]); - rc = ses->server->ops->check_receive(midQ, ses->server, - flags & CIFS_LOG_ERROR); + rc = ses->server->ops->check_receive(midQ[i], ses->server, + flags & CIFS_LOG_ERROR); - /* mark it so buf will not be freed by cifs_delete_mid */ - if ((flags & CIFS_NO_RESP) == 0) - midQ->resp_buf = NULL; + /* mark it so buf will not be freed by cifs_delete_mid */ + if ((flags & CIFS_NO_RESP) == 0) + midQ[i]->resp_buf = NULL; + } out: - cifs_delete_mid(midQ); + for (i = 0; i < num_rqst; i++) + cifs_delete_mid(midQ[i]); add_credits(ses->server, credits, optype); return rc; } int +cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, + struct smb_rqst *rqst, int *resp_buf_type, const int flags, + struct kvec *resp_iov) +{ + return compound_send_recv(xid, ses, flags, 1, rqst, resp_buf_type, + resp_iov); +} + +int SendReceive2(const unsigned int xid, struct cifs_ses *ses, struct kvec *iov, int n_vec, int *resp_buf_type /* ret */, const int flags, struct kvec *resp_iov) From patchwork Tue Feb 13 04:42:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872604 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVKy3Rs3z9sBZ for ; Tue, 13 Feb 2018 15:43:50 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933423AbeBMEnu (ORCPT ); Mon, 12 Feb 2018 23:43:50 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:33268 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933378AbeBMEnt (ORCPT ); Mon, 12 Feb 2018 23:43:49 -0500 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6BA1280125D6; Tue, 13 Feb 2018 04:43:49 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2AB0D2024CA1; Tue, 13 Feb 2018 04:43:47 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 10/14] cifs: fix memory leak in SMB2_open() Date: Tue, 13 Feb 2018 15:42:30 +1100 Message-Id: <20180213044234.18364-11-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 13 Feb 2018 04:43:49 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 13 Feb 2018 04:43:49 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Signed-off-by: Ronnie Sahlberg --- fs/cifs/smb2pdu.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index ac6b1d8d0c88..511c441c6b4f 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1773,8 +1773,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, rc = alloc_path_with_tree_prefix(©_path, ©_size, &name_len, tcon->treeName, path); - if (rc) + if (rc) { + cifs_small_buf_release(req); return rc; + } req->NameLength = cpu_to_le16(name_len * 2); uni_path_len = copy_size; path = copy_path; @@ -1785,8 +1787,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, if (uni_path_len % 8 != 0) { copy_size = roundup(uni_path_len, 8); copy_path = kzalloc(copy_size, GFP_KERNEL); - if (!copy_path) + if (!copy_path) { + cifs_small_buf_release(req); return -ENOMEM; + } memcpy((char *)copy_path, (const char *)path, uni_path_len); uni_path_len = copy_size; From patchwork Tue Feb 13 04:42:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872595 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVK75PNBz9sBZ for ; Tue, 13 Feb 2018 15:43:07 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933399AbeBMEnH (ORCPT ); Mon, 12 Feb 2018 23:43:07 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:39750 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933378AbeBMEnG (ORCPT ); Mon, 12 Feb 2018 23:43:06 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6BC5E402291E; Tue, 13 Feb 2018 04:43:06 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id EA49DAE7C8; Tue, 13 Feb 2018 04:43:04 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 11/14] cifs: create SMB2_open_init()/SMB2_open_free() helpers. Date: Tue, 13 Feb 2018 15:42:31 +1100 Message-Id: <20180213044234.18364-12-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 13 Feb 2018 04:43:06 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 13 Feb 2018 04:43:06 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Signed-off-by: Ronnie Sahlberg --- fs/cifs/smb2pdu.c | 131 +++++++++++++++++++++++++++------------------------- fs/cifs/smb2proto.h | 4 ++ 2 files changed, 73 insertions(+), 62 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 511c441c6b4f..f264d7605351 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1701,44 +1701,28 @@ 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 kvec *err_iov) +SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock, + struct cifs_open_parms *oparms, __le16 *path) { - struct smb_rqst rqst; + struct TCP_Server_Info *server = tcon->ses->server; struct smb2_create_req *req; - struct smb2_create_rsp *rsp; - struct TCP_Server_Info *server; - struct cifs_tcon *tcon = oparms->tcon; - struct cifs_ses *ses = tcon->ses; - struct kvec iov[4]; - struct kvec rsp_iov = {NULL, 0}; - int resp_buftype; - int uni_path_len; - __le16 *copy_path = NULL; - int copy_size; - int rc = 0; unsigned int n_iov = 2; __u32 file_attributes = 0; - char *dhc_buf = NULL, *lc_buf = NULL; - int flags = 0; + int copy_size; + int uni_path_len; unsigned int total_len; - - cifs_dbg(FYI, "create/open\n"); - - if (ses && (ses->server)) - server = ses->server; - else - return -EIO; + struct kvec *iov = rqst->rq_iov; + __le16 *copy_path; + int rc; rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len); + iov[0].iov_base = (char *)req; + /* -1 since last byte is buf[0] which is sent below (path) */ + iov[0].iov_len = total_len - 1; if (rc) return rc; - if (encryption_required(tcon)) - flags |= CIFS_TRANSFORM_REQ; - if (oparms->create_options & CREATE_OPTION_READONLY) file_attributes |= ATTR_READONLY; if (oparms->create_options & CREATE_OPTION_SPECIAL) @@ -1751,11 +1735,6 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, req->ShareAccess = FILE_SHARE_ALL_LE; req->CreateDisposition = cpu_to_le32(oparms->disposition); req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK); - - iov[0].iov_base = (char *)req; - /* -1 since last byte is buf[0] which is sent below (path) */ - iov[0].iov_len = total_len - 1; - req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req)); /* [MS-SMB2] 2.2.13 NameOffset: @@ -1773,10 +1752,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, rc = alloc_path_with_tree_prefix(©_path, ©_size, &name_len, tcon->treeName, path); - if (rc) { - cifs_small_buf_release(req); + if (rc) return rc; - } req->NameLength = cpu_to_le16(name_len * 2); uni_path_len = copy_size; path = copy_path; @@ -1784,18 +1761,17 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; /* MUST set path len (NameLength) to 0 opening root of share */ req->NameLength = cpu_to_le16(uni_path_len - 2); - if (uni_path_len % 8 != 0) { - copy_size = roundup(uni_path_len, 8); - copy_path = kzalloc(copy_size, GFP_KERNEL); - if (!copy_path) { - cifs_small_buf_release(req); - return -ENOMEM; - } - memcpy((char *)copy_path, (const char *)path, - uni_path_len); - uni_path_len = copy_size; - path = copy_path; + copy_size = uni_path_len; + if (copy_size % 8 != 0) { + copy_size = roundup(copy_size, 8); } + copy_path = kzalloc(copy_size, GFP_KERNEL); + if (!copy_path) + return -ENOMEM; + memcpy((char *)copy_path, (const char *)path, + uni_path_len); + uni_path_len = copy_size; + path = copy_path; } iov[1].iov_len = uni_path_len; @@ -1809,12 +1785,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, req->RequestedOplockLevel = *oplock; else { rc = add_lease_context(server, iov, &n_iov, oplock); - if (rc) { - cifs_small_buf_release(req); - kfree(copy_path); + if (rc) return rc; - } - lc_buf = iov[n_iov-1].iov_base; } if (*oplock == SMB2_OPLOCK_LEVEL_BATCH) { @@ -1828,22 +1800,59 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, rc = add_durable_context(iov, &n_iov, oparms, tcon->use_persistent); - if (rc) { - cifs_small_buf_release(req); - kfree(copy_path); - kfree(lc_buf); + if (rc) return rc; - } - dhc_buf = iov[n_iov-1].iov_base; } + rqst->rq_nvec = n_iov; + return 0; +} + +void +SMB2_open_free(struct smb_rqst *rqst) { + cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */ + kfree(rqst->rq_iov[1].iov_base); /* copy_path */ + kfree(rqst->rq_iov[2].iov_base); /* lc_buf */ + kfree(rqst->rq_iov[3].iov_base); /* dhc_buf */ +} + +int +SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, + __u8 *oplock, struct smb2_file_all_info *buf, + struct kvec *err_iov) +{ + struct smb_rqst rqst; + struct smb2_create_rsp *rsp = NULL; + struct TCP_Server_Info *server; + struct cifs_tcon *tcon = oparms->tcon; + struct cifs_ses *ses = tcon->ses; + struct kvec iov[4]; + struct kvec rsp_iov = {NULL, 0}; + int resp_buftype; + int rc = 0; + int flags = 0; + + cifs_dbg(FYI, "create/open\n"); + + if (ses && (ses->server)) + server = ses->server; + else + return -EIO; + + if (encryption_required(tcon)) + flags |= CIFS_TRANSFORM_REQ; + memset(&rqst, 0, sizeof(struct smb_rqst)); + memset(&iov, 0, sizeof(iov)); rqst.rq_iov = iov; - rqst.rq_nvec = n_iov; + rqst.rq_nvec = 4; + + rc = SMB2_open_init(tcon, &rqst, oplock, oparms, path); + if (rc) + goto creat_exit; rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); - cifs_small_buf_release(req); rsp = (struct smb2_create_rsp *)rsp_iov.iov_base; if (rc != 0) { @@ -1872,9 +1881,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, else *oplock = rsp->OplockLevel; creat_exit: - kfree(copy_path); - kfree(lc_buf); - kfree(dhc_buf); + SMB2_open_free(&rqst); free_rsp_buf(resp_buftype, rsp); return rc; } diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index d35e6bfa079d..06151df3c316 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -124,6 +124,10 @@ extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, __u8 *oplock, struct smb2_file_all_info *buf, struct kvec *err_iov); +extern int SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, + __u8 *oplock, struct cifs_open_parms *oparms, + __le16 *path); +extern void SMB2_open_free(struct smb_rqst *rqst); 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, From patchwork Tue Feb 13 04:42:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872601 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVKg0RDkz9sBZ for ; Tue, 13 Feb 2018 15:43:35 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933428AbeBMEne (ORCPT ); Mon, 12 Feb 2018 23:43:34 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:38360 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933378AbeBMEne (ORCPT ); Mon, 12 Feb 2018 23:43:34 -0500 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D62B54084FE8; Tue, 13 Feb 2018 04:43:33 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id 396072024CA1; Tue, 13 Feb 2018 04:43:31 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 12/14] cifs: add SMB2_close_init()/SMB2_close_free() Date: Tue, 13 Feb 2018 15:42:32 +1100 Message-Id: <20180213044234.18364-13-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 13 Feb 2018 04:43:33 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 13 Feb 2018 04:43:33 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Signed-off-by: Ronnie Sahlberg --- fs/cifs/smb2pdu.c | 48 ++++++++++++++++++++++++++++++++++-------------- fs/cifs/smb2proto.h | 3 +++ 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index f264d7605351..bd1ccfb10ec6 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2079,44 +2079,63 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, } int +SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, + u64 persistent_fid, u64 volatile_fid) +{ + struct smb2_close_req *req; + struct kvec *iov = rqst->rq_iov; + unsigned int total_len; + int rc; + + rc = smb2_plain_req_init(SMB2_CLOSE, tcon, (void **) &req, &total_len); + if (rc) + return rc; + + req->PersistentFileId = persistent_fid; + req->VolatileFileId = volatile_fid; + + iov[0].iov_base = (char *)req; + iov[0].iov_len = total_len; + + return 0; +} + +void +SMB2_close_free(struct smb_rqst *rqst) { + cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */ +} + +int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid) { struct smb_rqst rqst; - struct smb2_close_req *req; - struct smb2_close_rsp *rsp; + struct smb2_close_rsp *rsp = NULL; struct cifs_ses *ses = tcon->ses; struct kvec iov[1]; struct kvec rsp_iov; int resp_buftype; int rc = 0; int flags = 0; - unsigned int total_len; cifs_dbg(FYI, "Close\n"); if (!ses || !(ses->server)) return -EIO; - rc = smb2_plain_req_init(SMB2_CLOSE, tcon, (void **) &req, &total_len); - if (rc) - return rc; - if (encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; - req->PersistentFileId = persistent_fid; - req->VolatileFileId = volatile_fid; - - iov[0].iov_base = (char *)req; - iov[0].iov_len = total_len; - memset(&rqst, 0, sizeof(struct smb_rqst)); + memset(&iov, 0, sizeof(iov)); rqst.rq_iov = iov; rqst.rq_nvec = 1; + rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid); + if (rc) + goto close_exit; + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); - cifs_small_buf_release(req); rsp = (struct smb2_close_rsp *)rsp_iov.iov_base; if (rc != 0) { @@ -2127,6 +2146,7 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, /* BB FIXME - decode close response, update inode for caching */ close_exit: + SMB2_close_free(&rqst); free_rsp_buf(resp_buftype, rsp); return rc; } diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 06151df3c316..f31b9f3d060a 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -135,6 +135,9 @@ extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, char **out_data, u32 *plen /* returned data len */); extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id); +extern int SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, + u64 persistent_file_id, u64 volatile_file_id); +extern void SMB2_close_free(struct smb_rqst *rqst); extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id); extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, From patchwork Tue Feb 13 04:42:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872593 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVJy0KHnz9sP9 for ; Tue, 13 Feb 2018 15:42:57 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933218AbeBMEm4 (ORCPT ); Mon, 12 Feb 2018 23:42:56 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:42312 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933417AbeBMEm4 (ORCPT ); Mon, 12 Feb 2018 23:42:56 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C2D57E4486; Tue, 13 Feb 2018 04:42:55 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id 19BF7AE7C8; Tue, 13 Feb 2018 04:42:53 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 13/14] cifs: add SMB2_query_info_[init|free]() Date: Tue, 13 Feb 2018 15:42:33 +1100 Message-Id: <20180213044234.18364-14-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 13 Feb 2018 04:42:55 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 13 Feb 2018 04:42:55 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Signed-off-by: Ronnie Sahlberg --- fs/cifs/smb2pdu.c | 70 +++++++++++++++++++++++++++++++++++------------------ fs/cifs/smb2proto.h | 5 ++++ 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index bd1ccfb10ec6..2fa1b55fe6fa 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2206,36 +2206,23 @@ validate_and_copy_iov(unsigned int offset, unsigned int buffer_length, return 0; } -static int -query_info(const unsigned int xid, struct cifs_tcon *tcon, - u64 persistent_fid, u64 volatile_fid, u8 info_class, u8 info_type, - u32 additional_info, size_t output_len, size_t min_len, void **data, - u32 *dlen) + +int +SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, + u64 persistent_fid, u64 volatile_fid, + u8 info_class, u8 info_type, u32 additional_info, + size_t output_len) { - struct smb_rqst rqst; struct smb2_query_info_req *req; - struct smb2_query_info_rsp *rsp = NULL; - struct kvec iov[2]; - struct kvec rsp_iov; - int rc = 0; - int resp_buftype; - struct cifs_ses *ses = tcon->ses; - int flags = 0; + struct kvec *iov = rqst->rq_iov; unsigned int total_len; - - cifs_dbg(FYI, "Query Info\n"); - - if (!ses || !(ses->server)) - return -EIO; + int rc; rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req, &total_len); if (rc) return rc; - if (encryption_required(tcon)) - flags |= CIFS_TRANSFORM_REQ; - req->InfoType = info_type; req->FileInfoClass = info_class; req->PersistentFileId = persistent_fid; @@ -2246,19 +2233,55 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, * We do not use the input buffer (do not send extra byte) */ req->InputBufferOffset = 0; - req->OutputBufferLength = cpu_to_le32(output_len); iov[0].iov_base = (char *)req; /* 1 for Buffer */ iov[0].iov_len = total_len - 1; + return 0; +} + +void +SMB2_query_info_free(struct smb_rqst *rqst) { + cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */ +} + +static int +query_info(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, u8 info_class, u8 info_type, + u32 additional_info, size_t output_len, size_t min_len, void **data, + u32 *dlen) +{ + struct smb_rqst rqst; + struct smb2_query_info_rsp *rsp = NULL; + struct kvec iov[1]; + struct kvec rsp_iov; + int rc = 0; + int resp_buftype; + struct cifs_ses *ses = tcon->ses; + int flags = 0; + + cifs_dbg(FYI, "Query Info\n"); + + if (!ses || !(ses->server)) + return -EIO; + + if (encryption_required(tcon)) + flags |= CIFS_TRANSFORM_REQ; + memset(&rqst, 0, sizeof(struct smb_rqst)); + memset(&iov, 0, sizeof(iov)); rqst.rq_iov = iov; rqst.rq_nvec = 1; + rc = SMB2_query_info_init(tcon, &rqst, persistent_fid, volatile_fid, + info_class, info_type, additional_info, + output_len); + if (rc) + goto qinf_exit; + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); - cifs_small_buf_release(req); rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; if (rc) { @@ -2285,6 +2308,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, &rsp_iov, min_len, *data); qinf_exit: + SMB2_query_info_free(&rqst); free_rsp_buf(resp_buftype, rsp); return rc; } diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index f31b9f3d060a..5e6d46548bec 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -147,6 +147,11 @@ extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id, struct smb2_file_all_info *data); +extern int SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, + u64 persistent_fid, u64 volatile_fid, + u8 info_class, u8 info_type, + u32 additional_info, size_t output_len); +extern void SMB2_query_info_free(struct smb_rqst *rqst); extern int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id, void **data, unsigned int *plen); From patchwork Tue Feb 13 04:42:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 872600 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zgVKb3S6Fz9sBZ for ; Tue, 13 Feb 2018 15:43:31 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933431AbeBMEnb (ORCPT ); Mon, 12 Feb 2018 23:43:31 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:33256 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933378AbeBMEna (ORCPT ); Mon, 12 Feb 2018 23:43:30 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CD3438182D2E; Tue, 13 Feb 2018 04:43:29 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-34.bne.redhat.com [10.64.54.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4CA3EAE7C8; Tue, 13 Feb 2018 04:43:27 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 14/14] cifs: update smb2_queryfs() to use compounding Date: Tue, 13 Feb 2018 15:42:34 +1100 Message-Id: <20180213044234.18364-15-lsahlber@redhat.com> In-Reply-To: <20180213044234.18364-1-lsahlber@redhat.com> References: <20180213044234.18364-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 13 Feb 2018 04:43:29 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 13 Feb 2018 04:43:29 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Change smb2_queryfs() to use a Create/QueryInfo/Close compound request. Signed-off-by: Ronnie Sahlberg --- fs/cifs/cifsglob.h | 1 - fs/cifs/smb2ops.c | 119 ++++++++++++++++++++++++++++++++++++++++++---------- fs/cifs/smb2pdu.c | 70 +++++++++++++++---------------- fs/cifs/smb2pdu.h | 1 + fs/cifs/smb2proto.h | 5 +++ fs/cifs/transport.c | 2 +- 6 files changed, 140 insertions(+), 58 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a5ffcaf4b144..956558eb6a6b 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -450,7 +450,6 @@ struct smb_version_operations { enum securityEnum (*select_sectype)(struct TCP_Server_Info *, enum securityEnum); int (*next_header)(char *); - void (*set_next_header)(char *, int); }; struct smb_version_values { diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 80462bb3fd03..663ede43dfdf 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1281,15 +1281,64 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, CIFS_CACHE_READ(cinode) ? 1 : 0); } +static void +smb2_set_related(struct smb_rqst *rqst) +{ + struct smb2_sync_hdr *shdr; + + shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base); + shdr->Flags |= SMB2_FLAGS_RELATED_OPERATIONS; +} + +static void +smb2_set_next_command(struct smb_rqst *rqst) +{ + struct smb2_sync_hdr *shdr; + unsigned long len = smb2_rqst_len(rqst); + static char padding[7] = {0, 0, 0, 0, 0, 0, 0}; + + /* SMB headers in a compound are 8 byte aligned. */ + if (len & 7) { + rqst->rq_iov[rqst->rq_nvec].iov_base = padding; + rqst->rq_iov[rqst->rq_nvec].iov_len = 8 - (len & 7); + rqst->rq_nvec++; + len = smb2_rqst_len(rqst); + } + + shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base); + shdr->NextCommand = cpu_to_le32(len); +} + static int smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, struct kstatfs *buf) { - int rc; + struct smb2_query_info_rsp *rsp; + struct smb2_fs_full_size_info *info = NULL; + struct smb_rqst rqst[3]; + int resp_buftype[3]; + struct kvec rsp_iov[3]; + struct kvec open_iov[5]; /* 4 + potential padding. */ + struct kvec qi_iov[1]; + struct kvec close_iov[1]; + struct cifs_ses *ses = tcon->ses; __le16 srch_path = 0; /* Null - open root of share */ u8 oplock = SMB2_OPLOCK_LEVEL_NONE; struct cifs_open_parms oparms; struct cifs_fid fid; + int flags = 0; + int rc; + + if (smb3_encryption_required(tcon)) + flags |= CIFS_TRANSFORM_REQ; + + memset(rqst, 0, sizeof(rqst)); + memset(resp_buftype, 0, sizeof(resp_buftype)); + memset(rsp_iov, 0, sizeof(rsp_iov)); + + memset(&open_iov, 0, sizeof(open_iov)); + rqst[0].rq_iov = open_iov; + rqst[0].rq_nvec = 4; oparms.tcon = tcon; oparms.desired_access = FILE_READ_ATTRIBUTES; @@ -1298,13 +1347,56 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, oparms.fid = &fid; oparms.reconnect = false; - rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL); + rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, &srch_path); if (rc) - return rc; + goto qfs_exit; + smb2_set_next_command(&rqst[0]); + + memset(&qi_iov, 0, sizeof(qi_iov)); + rqst[1].rq_iov = qi_iov; + rqst[1].rq_nvec = 1; + + rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID, + FS_FULL_SIZE_INFORMATION, + SMB2_O_INFO_FILESYSTEM, 0, + sizeof(struct smb2_fs_full_size_info)); + if (rc) + goto qfs_exit; + smb2_set_next_command(&rqst[1]); + smb2_set_related(&rqst[1]); + + memset(&close_iov, 0, sizeof(close_iov)); + rqst[2].rq_iov = close_iov; + rqst[2].rq_nvec = 1; + + rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID); + if (rc) + goto qfs_exit; + smb2_set_related(&rqst[2]); + + rc = compound_send_recv(xid, ses, flags, 3, rqst, + resp_buftype, rsp_iov); + if (rc) + goto qfs_exit; + + rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; buf->f_type = SMB2_MAGIC_NUMBER; - rc = SMB2_QFS_info(xid, tcon, fid.persistent_fid, fid.volatile_fid, - buf); - SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); + info = (struct smb2_fs_full_size_info *)( + le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp); + rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), + le32_to_cpu(rsp->OutputBufferLength), + &rsp_iov[1], + sizeof(struct smb2_fs_full_size_info)); + if (!rc) + smb2_copy_fs_info_to_kstatfs(info, buf); + +qfs_exit: + SMB2_open_free(&rqst[0]); + SMB2_query_info_free(&rqst[1]); + SMB2_close_free(&rqst[2]); + free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); + free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); + free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); return rc; } @@ -2751,17 +2843,6 @@ smb2_next_header(char *buf) return le32_to_cpu(hdr->NextCommand); } -static void -smb2_set_next_header(char *buf, int offset) -{ - struct smb2_sync_hdr *hdr = (struct smb2_sync_hdr *)buf; - - if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) - return; - - hdr->NextCommand = cpu_to_le32(offset); -} - struct smb_version_operations smb20_operations = { .compare_fids = smb2_compare_fids, .setup_request = smb2_setup_request, @@ -2854,7 +2935,6 @@ struct smb_version_operations smb20_operations = { .set_acl = set_smb2_acl, #endif /* CIFS_ACL */ .next_header = smb2_next_header, - .set_next_header = smb2_set_next_header, }; struct smb_version_operations smb21_operations = { @@ -2950,7 +3030,6 @@ struct smb_version_operations smb21_operations = { .set_acl = set_smb2_acl, #endif /* CIFS_ACL */ .next_header = smb2_next_header, - .set_next_header = smb2_set_next_header, }; struct smb_version_operations smb30_operations = { @@ -3056,7 +3135,6 @@ struct smb_version_operations smb30_operations = { .set_acl = set_smb2_acl, #endif /* CIFS_ACL */ .next_header = smb2_next_header, - .set_next_header = smb2_set_next_header, }; #ifdef CONFIG_CIFS_SMB311 @@ -3158,7 +3236,6 @@ struct smb_version_operations smb311_operations = { .set_EA = smb2_set_ea, #endif /* CIFS_XATTR */ .next_header = smb2_next_header, - .set_next_header = smb2_set_next_header, }; #endif /* CIFS_SMB311 */ diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 2fa1b55fe6fa..1938294bf056 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -78,7 +78,7 @@ static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { /* SMB2_OPLOCK_BREAK */ 24 /* BB this is 36 for LEASE_BREAK variant */ }; -static int encryption_required(const struct cifs_tcon *tcon) +int smb3_encryption_required(const struct cifs_tcon *tcon) { if (!tcon) return 0; @@ -144,7 +144,7 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd, shdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */ if (tcon->ses && tcon->ses->server && tcon->ses->server->sign && - !encryption_required(tcon)) + !smb3_encryption_required(tcon)) shdr->Flags |= SMB2_FLAGS_SIGNED; out: return; @@ -1286,7 +1286,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, req->sync_hdr.SessionId = ses->Suid; if (ses->server->sign) req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED; - } else if (encryption_required(tcon)) + } else if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; iov[0].iov_base = (char *)req; @@ -1396,7 +1396,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) if (rc) return rc; - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; flags |= CIFS_NO_RESP; @@ -1839,7 +1839,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, else return -EIO; - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; memset(&rqst, 0, sizeof(struct smb_rqst)); @@ -1938,7 +1938,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, req->sync_hdr.TreeId, ses->ipc_tid); req->sync_hdr.TreeId = ses->ipc_tid; } - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; req->CtlCode = cpu_to_le32(opcode); @@ -2123,7 +2123,7 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, if (!ses || !(ses->server)) return -EIO; - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; memset(&rqst, 0, sizeof(struct smb_rqst)); @@ -2151,9 +2151,9 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -static int -validate_iov(unsigned int offset, unsigned int buffer_length, - struct kvec *iov, unsigned int min_buf_size) +int +smb2_validate_iov(unsigned int offset, unsigned int buffer_length, + struct kvec *iov, unsigned int min_buf_size) { unsigned int smb_len = iov->iov_len; char *end_of_smb = smb_len + (char *)iov->iov_base; @@ -2197,7 +2197,7 @@ validate_and_copy_iov(unsigned int offset, unsigned int buffer_length, if (!data) return -EINVAL; - rc = validate_iov(offset, buffer_length, iov, minbufsize); + rc = smb2_validate_iov(offset, buffer_length, iov, minbufsize); if (rc) return rc; @@ -2267,7 +2267,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, if (!ses || !(ses->server)) return -EIO; - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; memset(&rqst, 0, sizeof(struct smb_rqst)); @@ -2497,7 +2497,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, if (rc) return rc; - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; req->PersistentFileId = persistent_fid; @@ -2681,7 +2681,7 @@ smb2_async_readv(struct cifs_readdata *rdata) return rc; } - if (encryption_required(io_parms.tcon)) + if (smb3_encryption_required(io_parms.tcon)) flags |= CIFS_TRANSFORM_REQ; rdata->iov[0].iov_base = buf; @@ -2733,7 +2733,7 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, if (rc) return rc; - if (encryption_required(io_parms->tcon)) + if (smb3_encryption_required(io_parms->tcon)) flags |= CIFS_TRANSFORM_REQ; iov[0].iov_base = (char *)req; @@ -2858,7 +2858,7 @@ smb2_async_writev(struct cifs_writedata *wdata, goto async_writev_out; } - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; shdr = (struct smb2_sync_hdr *)req; @@ -2947,7 +2947,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, if (io_parms->tcon->ses->server == NULL) return -ECONNABORTED; - if (encryption_required(io_parms->tcon)) + if (smb3_encryption_required(io_parms->tcon)) flags |= CIFS_TRANSFORM_REQ; req->sync_hdr.ProcessId = cpu_to_le32(io_parms->pid); @@ -3062,7 +3062,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, if (rc) return rc; - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; switch (srch_inf->info_level) { @@ -3125,9 +3125,9 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, goto qdir_exit; } - rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset), - le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, - info_buf_size); + rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), + le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, + info_buf_size); if (rc) goto qdir_exit; @@ -3198,7 +3198,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, return rc; } - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; req->sync_hdr.ProcessId = cpu_to_le32(pid); @@ -3398,7 +3398,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, if (rc) return rc; - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; req->VolatileFid = volatile_fid; @@ -3426,9 +3426,9 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -static void -copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, - struct kstatfs *kst) +void +smb2_copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, + struct kstatfs *kst) { kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) * le32_to_cpu(pfs_inf->SectorsPerAllocationUnit); @@ -3491,7 +3491,7 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, if (rc) return rc; - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; memset(&rqst, 0, sizeof(struct smb_rqst)); @@ -3508,11 +3508,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, 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)); + rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), + le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, + sizeof(struct smb2_fs_full_size_info)); if (!rc) - copy_fs_info_to_kstatfs(info, fsdata); + smb2_copy_fs_info_to_kstatfs(info, fsdata); qfsinf_exit: free_rsp_buf(resp_buftype, rsp_iov.iov_base); @@ -3552,7 +3552,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, if (rc) return rc; - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; memset(&rqst, 0, sizeof(struct smb_rqst)); @@ -3569,7 +3569,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, rsp_len = le32_to_cpu(rsp->OutputBufferLength); offset = le16_to_cpu(rsp->OutputBufferOffset); - rc = validate_iov(offset, rsp_len, &rsp_iov, min_len); + rc = smb2_validate_iov(offset, rsp_len, &rsp_iov, min_len); if (rc) goto qfsattr_exit; @@ -3614,7 +3614,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, if (rc) return rc; - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; req->sync_hdr.ProcessId = cpu_to_le32(pid); @@ -3684,7 +3684,7 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, if (rc) return rc; - if (encryption_required(tcon)) + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; req->sync_hdr.CreditRequest = cpu_to_le16(1); diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 91fd17f5c2eb..2ab187202e71 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -152,6 +152,7 @@ struct smb2_transform_hdr { * command code name for the struct. Note that structures must be packed. * */ +#define COMPOUND_FID 0xffffffffffffffff #define SMB2_ERROR_STRUCTURE_SIZE2 cpu_to_le16(9) diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 5e6d46548bec..d59c628a232a 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -217,4 +217,9 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, enum securityEnum); extern int smb3_encryption_required(const struct cifs_tcon *tcon); +extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length, + struct kvec *iov, unsigned int min_buf_size); +extern void smb2_copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, + struct kstatfs *kst); +extern unsigned long smb2_rqst_len(struct smb_rqst *rqst); #endif /* _SMB2PROTO_H */ diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index d810d4af33ad..676fc5261fbf 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -199,7 +199,7 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, return 0; } -static unsigned long +unsigned long smb2_rqst_len(struct smb_rqst *rqst) { unsigned int i;