From patchwork Mon Mar 19 22:49:49 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 10295761 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 1F04160386 for ; Mon, 19 Mar 2018 22:51:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 09E1529297 for ; Mon, 19 Mar 2018 22:51:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F25ED294A0; Mon, 19 Mar 2018 22:51:19 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4CDB029297 for ; Mon, 19 Mar 2018 22:51:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755391AbeCSWvQ (ORCPT ); Mon, 19 Mar 2018 18:51:16 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:60844 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754668AbeCSWvP (ORCPT ); Mon, 19 Mar 2018 18:51:15 -0400 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 CB8EB40006E6; Mon, 19 Mar 2018 22:51:14 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-41.bne.redhat.com [10.64.54.41]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7886D218CC10; Mon, 19 Mar 2018 22:51:11 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 02/15] cifs: remove rfc1002 header from all SMB2 response structures Date: Tue, 20 Mar 2018 09:49:49 +1100 Message-Id: <20180319225002.7451-3-lsahlber@redhat.com> In-Reply-To: <20180319225002.7451-1-lsahlber@redhat.com> References: <20180319225002.7451-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.5]); Mon, 19 Mar 2018 22:51:14 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 19 Mar 2018 22:51:14 +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 X-Virus-Scanned: ClamAV using ClamSMTP 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 | 3 + fs/cifs/cifssmb.c | 2 +- fs/cifs/connect.c | 10 ++- fs/cifs/misc.c | 2 +- fs/cifs/smb2glob.h | 5 -- fs/cifs/smb2maperror.c | 2 +- fs/cifs/smb2misc.c | 100 +++++++++++++---------------- fs/cifs/smb2ops.c | 167 +++++++++++++++++++++++++++--------------------- fs/cifs/smb2pdu.c | 103 ++++++++++++++--------------- fs/cifs/smb2pdu.h | 65 ++++++------------- fs/cifs/smb2proto.h | 5 +- fs/cifs/smb2transport.c | 12 ++-- fs/cifs/transport.c | 3 +- 13 files changed, 229 insertions(+), 250 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 3e3f86841372..0045d85ec76d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -665,6 +665,8 @@ 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 */ + /* Total size of this PDU. Only valid from cifs_demultiplex_thread */ + unsigned int pdu_size; unsigned int total_read; /* total amount of data read in this pass */ #ifdef CONFIG_CIFS_FSCACHE struct fscache_cookie *fscache; /* client index cache cookie */ @@ -1373,6 +1375,7 @@ struct mid_q_entry { mid_handle_t *handle; /* call handle mid callback */ void *callback_data; /* general purpose pointer for callback */ void *resp_buf; /* pointer to received SMB header */ + unsigned int resp_buf_size; int mid_state; /* wish this were enum but can not pass to wait_event */ unsigned int mid_flags; __le16 command; /* smb command code */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 59c09a596c0a..991e9d9ef90a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1454,7 +1454,7 @@ 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) + + unsigned int buflen = server->pdu_size + server->vals->header_preamble_size; bool use_rdma_mr = false; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 1f2e3b15b2b1..0fad48d081d8 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -772,7 +772,7 @@ 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->pdu_size; /* make sure this will fit in a large buffer */ if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) - @@ -874,13 +874,18 @@ 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->pdu_size = pdu_length; cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length); if (!is_smb_response(server, buf[0])) @@ -927,6 +932,7 @@ cifs_demultiplex_thread(void *p) server->lstrp = jiffies; if (mid_entry != NULL) { + mid_entry->resp_buf_size = server->pdu_size; if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) && mid_entry->mid_state == MID_RESPONSE_RECEIVED && server->ops->handle_cancelled_mid) diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 460084a8eac5..d5d7eb2ae3c4 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -145,7 +145,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/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..8fe30288805f 100644 --- a/fs/cifs/smb2maperror.c +++ b/fs/cifs/smb2maperror.c @@ -2450,7 +2450,7 @@ 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 = (struct smb2_sync_hdr *)buf; unsigned int i; int rc = -EIO; __le32 smb2err = shdr->Status; diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index da012c3ab700..e5e04321485e 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -96,23 +96,18 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { int smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) { - struct smb2_pdu *pdu = (struct smb2_pdu *)buf; - struct smb2_hdr *hdr = &pdu->hdr; - struct smb2_sync_hdr *shdr = get_sync_hdr(buf); + struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; + struct smb2_sync_pdu *pdu = (struct smb2_sync_pdu *)shdr; __u64 mid; - __u32 len = get_rfc1002_length(buf); __u32 clc_len; /* calculated length */ int command; - - /* BB disable following printk later */ - cifs_dbg(FYI, "%s length: 0x%x, smb_buf_length: 0x%x\n", - __func__, length, len); + int pdu_size = sizeof(struct smb2_sync_pdu); + int hdr_size = sizeof(struct smb2_sync_hdr); /* * 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 +131,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 +145,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 +184,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(hdr); + clc_len = smb2_calc_size(buf); - 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 +207,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 +251,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 +270,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_sess_setup_rsp *)shdr)->SecurityBufferOffset); *len = le16_to_cpu( - ((struct smb2_negotiate_rsp *)hdr)->SecurityBufferLength); + ((struct smb2_sess_setup_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 +352,12 @@ 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_pdu *)buf; + struct smb2_sync_hdr *shdr = &pdu->sync_hdr; 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 = le16_to_cpu(shdr->StructureSize); /* * StructureSize2, ie length of fixed parameter area has already @@ -379,7 +368,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 +376,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 +566,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 +575,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,8 +666,8 @@ 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_sync_hdr *)buffer; + struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)sync_hdr; struct cifs_tcon *tcon; struct close_cancelled_open *cancelled; diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index ad4eba0c7e63..ae371cd451f8 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -123,7 +123,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); } @@ -190,7 +191,7 @@ 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); + struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; __u64 wire_mid = le64_to_cpu(shdr->MessageId); if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { @@ -215,7 +216,7 @@ 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 = (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, @@ -1241,7 +1242,7 @@ 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 = (struct smb2_sync_hdr *)buf; if (shdr->Status != STATUS_PENDING) return false; @@ -1259,7 +1260,7 @@ 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 = (struct smb2_sync_hdr *)buf; if (shdr->Status != STATUS_NETWORK_SESSION_EXPIRED) return false; @@ -1451,6 +1452,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; @@ -1471,15 +1473,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; } @@ -1492,13 +1495,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; @@ -2050,11 +2053,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; @@ -2062,8 +2065,6 @@ 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); } /* We can not use the normal sg_set_buf() as we will sometimes pass a @@ -2075,11 +2076,16 @@ static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf, sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf)); } +/* Assumes: + * rqst->rq_iov[0] is rfc1002 length + * rqst->rq_iov[1] is tranform header + * rqst->rq_iov[2+] data to be encrypted/decrypted + */ static struct scatterlist * init_sg(struct smb_rqst *rqst, u8 *sign) { - unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1; - unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24; + unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages; + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; struct scatterlist *sg; unsigned int i; unsigned int j; @@ -2089,10 +2095,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign) return NULL; sg_init_table(sg, sg_len); - smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len); - for (i = 1; i < rqst->rq_nvec; i++) - smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base, - rqst->rq_iov[i].iov_len); + smb2_sg_set_buf(&sg[0], rqst->rq_iov[1].iov_base + 20, assoc_data_len); + for (i = 1; i < rqst->rq_nvec - 1; i++) + smb2_sg_set_buf(&sg[i], rqst->rq_iov[i+1].iov_base, + rqst->rq_iov[i+1].iov_len); for (j = 0; i < sg_len - 1; i++, j++) { unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz : rqst->rq_tailsz; @@ -2124,17 +2130,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] = {}; @@ -2221,6 +2228,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) @@ -2229,6 +2239,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; @@ -2247,24 +2258,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++) { @@ -2304,7 +2325,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); } @@ -2321,18 +2342,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; @@ -2344,10 +2366,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; } @@ -2420,7 +2441,7 @@ 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 smb2_sync_hdr *)buf; struct bio_vec *bvec = NULL; struct iov_iter iter; struct kvec iov; @@ -2451,7 +2472,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, return 0; } - data_offset = server->ops->read_data_offset(buf) + 4; + data_offset = server->ops->read_data_offset(buf); #ifdef CONFIG_CIFS_SMB_DIRECT use_rdma_mr = rdata->mr; #endif @@ -2547,11 +2568,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->pdu_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); @@ -2559,7 +2580,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); @@ -2586,7 +2607,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; @@ -2618,12 +2639,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->pdu_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; @@ -2631,12 +2652,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; @@ -2661,12 +2682,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->pdu_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); @@ -2674,14 +2695,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); @@ -2692,7 +2713,7 @@ smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid) { char *buf = server->large_buf ? server->bigbuf : server->smallbuf; - return handle_read_data(server, mid, buf, get_rfc1002_length(buf) + 4, + return handle_read_data(server, mid, buf, server->total_read, NULL, 0, 0); } @@ -3096,8 +3117,8 @@ struct smb_version_values smb20_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), - .header_preamble_size = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, @@ -3117,8 +3138,8 @@ struct smb_version_values smb21_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), - .header_preamble_size = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, @@ -3138,8 +3159,8 @@ struct smb_version_values smb3any_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), - .header_preamble_size = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, @@ -3159,8 +3180,8 @@ struct smb_version_values smbdefault_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), - .header_preamble_size = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, @@ -3180,8 +3201,8 @@ struct smb_version_values smb30_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), - .header_preamble_size = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, @@ -3201,8 +3222,8 @@ struct smb_version_values smb302_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), - .header_preamble_size = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, @@ -3223,8 +3244,8 @@ struct smb_version_values smb311_values = { .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, - .header_size = sizeof(struct smb2_hdr), - .header_preamble_size = 4, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, .lock_cmd = SMB2_LOCK, diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 4b6920de2541..b20348f72a6f 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -591,7 +591,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 @@ -942,7 +942,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); @@ -1018,13 +1018,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)); @@ -1039,7 +1039,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: @@ -1097,7 +1097,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); @@ -1340,7 +1340,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) && @@ -1360,7 +1360,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; @@ -1466,7 +1466,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)) { @@ -1694,7 +1694,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; @@ -1834,9 +1834,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; } @@ -1875,7 +1876,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; @@ -1996,7 +1996,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; @@ -2010,8 +2010,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; @@ -2091,13 +2090,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; @@ -2127,18 +2125,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; @@ -2216,9 +2213,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); @@ -2287,7 +2284,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); @@ -2684,7 +2681,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; @@ -2725,10 +2721,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; @@ -2755,7 +2749,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; @@ -3131,7 +3125,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; } @@ -3139,8 +3133,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; @@ -3154,10 +3148,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); @@ -3393,7 +3386,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; @@ -3469,7 +3462,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; @@ -3506,10 +3499,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); @@ -3564,20 +3557,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 8b901c69a65a..6bf243a45d64 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 */ @@ -289,7 +274,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; @@ -329,7 +314,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; @@ -344,7 +329,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; @@ -440,7 +425,7 @@ struct smb2_tree_connect_req_extension { } __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; @@ -491,7 +476,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; @@ -626,7 +611,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; @@ -882,7 +867,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; @@ -909,7 +894,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; @@ -932,7 +917,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; @@ -964,7 +949,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; @@ -995,7 +980,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; @@ -1029,7 +1014,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; @@ -1041,7 +1026,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; @@ -1067,7 +1052,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; @@ -1116,7 +1101,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; @@ -1138,12 +1123,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; @@ -1153,21 +1137,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 cbcce3f7e86f..30cdc0aa4e8e 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, char *in_data, u32 indatalen, diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index bf49cb73b9e6..8372a0cecdb0 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -480,7 +480,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) unsigned int rc; char server_response_sig[16]; struct smb2_sync_hdr *shdr = - (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base; + (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; if ((shdr->Command == SMB2_NEGOTIATE) || (shdr->Command == SMB2_SESSION_SETUP) || @@ -604,15 +604,13 @@ int 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]; + unsigned int len = server->total_read; + struct kvec iov[1]; struct smb_rqst rqst = { .rq_iov = iov, - .rq_nvec = 2 }; + .rq_nvec = 1 }; iov[0].iov_base = (char *)mid->resp_buf; - iov[0].iov_len = 4; - iov[1].iov_base = (char *)mid->resp_buf + 4; - iov[1].iov_len = len; + iov[0].iov_len = mid->resp_buf_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 279718dcb2ed..3abce580b056 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -790,8 +790,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) + + resp_iov->iov_len = midQ->resp_buf_size + ses->server->vals->header_preamble_size; + if (midQ->large_buf) *resp_buf_type = CIFS_LARGE_BUFFER; else