From 6d2f84eee098540ae857998fe32f29b9e2cd9613 Mon Sep 17 00:00:00 2001 From: Paul Aurich Date: Mon, 31 Dec 2018 14:13:34 -0800 Subject: [PATCH 1/3] smb3: fix large reads on encrypted connections When passing a large read to receive_encrypted_read(), ensure that the demultiplex_thread knows that a MID was processed. Without this, those operations never complete. This is a similar issue/fix to lease break handling: commit 7af929d6d05ba5564139718e30d5bc96bdbc716a ("smb3: fix lease break problem introduced by compounding") CC: Stable # 4.19+ Fixes: b24df3e30cbf ("cifs: update receive_encrypted_standard to handle compounded responses") Signed-off-by: Paul Aurich Tested-by: Yves-Alexis Perez Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg --- fs/cifs/smb2ops.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 33100ef74d7f..cf7eb891804f 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -3472,8 +3472,10 @@ smb3_receive_transform(struct TCP_Server_Info *server, } /* TODO: add support for compounds containing READ. */ - if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) + if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) { + *num_mids = 1; return receive_encrypted_read(server, &mids[0]); + } return receive_encrypted_standard(server, mids, bufs, num_mids); } From 55a7f0065533f71991c720457ea24ff2fe909f81 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 1 Jan 2019 17:19:45 -0600 Subject: [PATCH 2/3] cifs: fix confusing warning message on reconnect When DFS is not used on the mount we should not be mentioning DFS in the warning message on reconnect (it could be confusing). Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg --- fs/cifs/connect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 69b9d5606eba..f66529679ca2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -483,7 +483,7 @@ cifs_reconnect(struct TCP_Server_Info *server) cifs_sb = NULL; } else { rc = reconn_setup_dfs_targets(cifs_sb, &tgt_list, &tgt_it); - if (rc) { + if (rc && (rc != -EOPNOTSUPP)) { cifs_dbg(VFS, "%s: no target servers for DFS failover\n", __func__); } else { From d5c7076b772ad7dcdb92303397b36aee8fa0d25d Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 3 Jan 2019 02:37:21 -0600 Subject: [PATCH 3/3] smb3: add smb3.1.1 to default dialect list SMB3.1.1 dialect has additional security (among other) features and should be requested when mounting to modern servers so it can be used if the server supports it. Add SMB3.1.1 to the default list of dialects requested. Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg --- fs/cifs/smb2pdu.c | 40 +++++++++++++++++++++++++++------------- fs/cifs/smb2pdu.h | 2 +- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index e283590955cd..e57f6aa1d638 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -451,10 +451,6 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon, } -/* offset is sizeof smb2_negotiate_req but rounded up to 8 bytes */ -#define OFFSET_OF_NEG_CONTEXT 0x68 /* sizeof(struct smb2_negotiate_req) */ - - #define SMB2_PREAUTH_INTEGRITY_CAPABILITIES cpu_to_le16(1) #define SMB2_ENCRYPTION_CAPABILITIES cpu_to_le16(2) #define SMB2_POSIX_EXTENSIONS_AVAILABLE cpu_to_le16(0x100) @@ -491,10 +487,24 @@ static void assemble_neg_contexts(struct smb2_negotiate_req *req, unsigned int *total_len) { - char *pneg_ctxt = (char *)req + OFFSET_OF_NEG_CONTEXT; + char *pneg_ctxt = (char *)req; unsigned int ctxt_len; - *total_len += 2; /* Add 2 due to round to 8 byte boundary for 1st ctxt */ + if (*total_len > 200) { + /* In case length corrupted don't want to overrun smb buffer */ + cifs_dbg(VFS, "Bad frame length assembling neg contexts\n"); + return; + } + + /* + * round up total_len of fixed part of SMB3 negotiate request to 8 + * byte boundary before adding negotiate contexts + */ + *total_len = roundup(*total_len, 8); + + pneg_ctxt = (*total_len) + (char *)req; + req->NegotiateContextOffset = cpu_to_le32(*total_len); + build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt); ctxt_len = DIV_ROUND_UP(sizeof(struct smb2_preauth_neg_context), 8) * 8; *total_len += ctxt_len; @@ -508,7 +518,6 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt); *total_len += sizeof(struct smb2_posix_neg_context); - req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT); req->NegotiateContextCount = cpu_to_le16(3); } @@ -724,8 +733,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) req->Dialects[0] = cpu_to_le16(SMB21_PROT_ID); req->Dialects[1] = cpu_to_le16(SMB30_PROT_ID); req->Dialects[2] = cpu_to_le16(SMB302_PROT_ID); - req->DialectCount = cpu_to_le16(3); - total_len += 6; + req->Dialects[3] = cpu_to_le16(SMB311_PROT_ID); + req->DialectCount = cpu_to_le16(4); + total_len += 8; } else { /* otherwise send specific dialect */ req->Dialects[0] = cpu_to_le16(ses->server->vals->protocol_id); @@ -749,7 +759,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) else { memcpy(req->ClientGUID, server->client_guid, SMB2_CLIENT_GUID_SIZE); - if (ses->server->vals->protocol_id == SMB311_PROT_ID) + if ((ses->server->vals->protocol_id == SMB311_PROT_ID) || + (strcmp(ses->server->vals->version_string, + SMBDEFAULT_VERSION_STRING) == 0)) assemble_neg_contexts(req, &total_len); } iov[0].iov_base = (char *)req; @@ -794,7 +806,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) { /* ops set to 3.0 by default for default so update */ ses->server->ops = &smb21_operations; - } + } else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) + ses->server->ops = &smb311_operations; } else if (le16_to_cpu(rsp->DialectRevision) != ses->server->vals->protocol_id) { /* if requested single dialect ensure returned dialect matched */ @@ -941,13 +954,14 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) pneg_inbuf->DialectCount = cpu_to_le16(2); /* structure is big enough for 3 dialects, sending only 2 */ inbuflen = sizeof(*pneg_inbuf) - - sizeof(pneg_inbuf->Dialects[0]); + (2 * sizeof(pneg_inbuf->Dialects[0])); } else if (strcmp(tcon->ses->server->vals->version_string, SMBDEFAULT_VERSION_STRING) == 0) { pneg_inbuf->Dialects[0] = cpu_to_le16(SMB21_PROT_ID); pneg_inbuf->Dialects[1] = cpu_to_le16(SMB30_PROT_ID); pneg_inbuf->Dialects[2] = cpu_to_le16(SMB302_PROT_ID); - pneg_inbuf->DialectCount = cpu_to_le16(3); + pneg_inbuf->Dialects[3] = cpu_to_le16(SMB311_PROT_ID); + pneg_inbuf->DialectCount = cpu_to_le16(4); /* structure is big enough for 3 dialects */ inbuflen = sizeof(*pneg_inbuf); } else { diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 05dea6750c33..7a2d0a2255e6 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -898,7 +898,7 @@ struct validate_negotiate_info_req { __u8 Guid[SMB2_CLIENT_GUID_SIZE]; __le16 SecurityMode; __le16 DialectCount; - __le16 Dialects[3]; /* BB expand this if autonegotiate > 3 dialects */ + __le16 Dialects[4]; /* BB expand this if autonegotiate > 4 dialects */ } __packed; struct validate_negotiate_info_rsp {