smb3: negotiate current dialect (SMB3.1.1) when version 3 or greater requested
authorSteve French <stfrench@microsoft.com>
Tue, 2 Feb 2021 06:03:58 +0000 (00:03 -0600)
committerSteve French <stfrench@microsoft.com>
Mon, 15 Feb 2021 16:33:34 +0000 (10:33 -0600)
SMB3.1.1 is the newest, and preferred dialect, and is included in
the requested dialect list by default (ie if no vers= is specified
on mount) but it should also be requested if SMB3 or later is requested
(vers=3 instead of a specific dialect: vers=2.1, vers=3.02 or vers=3.0).

Currently specifying "vers=3" only requests smb3.0 and smb3.02 but this
patch fixes it to also request smb3.1.1 dialect, as it is the newest
and most secure dialect and is a "version 3 or later" dialect (the intent
of "vers=3").

Signed-off-by: Steve French <stfrench@microsoft.com>
Suggested-by: Pavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: Shyam Prasad N <sprasad@microsoft.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/fs_context.c
fs/cifs/smb2pdu.c

index 12a5da0..7d04f22 100644 (file)
@@ -397,7 +397,7 @@ cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3)
                ctx->vals = &smb3any_values;
                break;
        case Smb_default:
-               ctx->ops = &smb30_operations; /* currently identical with 3.0 */
+               ctx->ops = &smb30_operations;
                ctx->vals = &smbdefault_values;
                break;
        default:
index 794fc3b..e1391bd 100644 (file)
@@ -814,8 +814,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
                   SMB3ANY_VERSION_STRING) == 0) {
                req->Dialects[0] = cpu_to_le16(SMB30_PROT_ID);
                req->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
-               req->DialectCount = cpu_to_le16(2);
-               total_len += 4;
+               req->Dialects[2] = cpu_to_le16(SMB311_PROT_ID);
+               req->DialectCount = cpu_to_le16(3);
+               total_len += 6;
        } else if (strcmp(server->vals->version_string,
                   SMBDEFAULT_VERSION_STRING) == 0) {
                req->Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
@@ -849,6 +850,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
                        SMB2_CLIENT_GUID_SIZE);
                if ((server->vals->protocol_id == SMB311_PROT_ID) ||
                    (strcmp(server->vals->version_string,
+                    SMB3ANY_VERSION_STRING) == 0) ||
+                   (strcmp(server->vals->version_string,
                     SMBDEFAULT_VERSION_STRING) == 0))
                        assemble_neg_contexts(req, server, &total_len);
        }
@@ -883,6 +886,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
                        cifs_server_dbg(VFS,
                                "SMB2.1 dialect returned but not requested\n");
                        return -EIO;
+               } else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
+                       /* ops set to 3.0 by default for default so update */
+                       server->ops = &smb311_operations;
+                       server->vals = &smb311_values;
                }
        } else if (strcmp(server->vals->version_string,
                   SMBDEFAULT_VERSION_STRING) == 0) {
@@ -1042,10 +1049,11 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
                SMB3ANY_VERSION_STRING) == 0) {
                pneg_inbuf->Dialects[0] = cpu_to_le16(SMB30_PROT_ID);
                pneg_inbuf->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
-               pneg_inbuf->DialectCount = cpu_to_le16(2);
-               /* structure is big enough for 3 dialects, sending only 2 */
+               pneg_inbuf->Dialects[2] = cpu_to_le16(SMB311_PROT_ID);
+               pneg_inbuf->DialectCount = cpu_to_le16(3);
+               /* SMB 2.1 not included so subtract one dialect from len */
                inbuflen = sizeof(*pneg_inbuf) -
-                               (2 * sizeof(pneg_inbuf->Dialects[0]));
+                               (sizeof(pneg_inbuf->Dialects[0]));
        } else if (strcmp(server->vals->version_string,
                SMBDEFAULT_VERSION_STRING) == 0) {
                pneg_inbuf->Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
@@ -1053,7 +1061,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
                pneg_inbuf->Dialects[2] = cpu_to_le16(SMB302_PROT_ID);
                pneg_inbuf->Dialects[3] = cpu_to_le16(SMB311_PROT_ID);
                pneg_inbuf->DialectCount = cpu_to_le16(4);
-               /* structure is big enough for 3 dialects */
+               /* structure is big enough for 4 dialects */
                inbuflen = sizeof(*pneg_inbuf);
        } else {
                /* otherwise specific dialect was requested */