cifs: Fix validation of signed data in smb3+
authorPaulo Alcantara <paulo@paulo.ac>
Sat, 23 Jun 2018 17:52:23 +0000 (14:52 -0300)
committerSteve French <stfrench@microsoft.com>
Thu, 5 Jul 2018 18:48:24 +0000 (13:48 -0500)
Fixes: c713c8770fa5 ("cifs: push rfc1002 generation down the stack")
We failed to validate signed data returned by the server because
__cifs_calc_signature() now expects to sign the actual data in iov but
we were also passing down the rfc1002 length.

Fix smb3_calc_signature() to calculate signature of rfc1002 length prior
to passing only the actual data iov[1-N] to __cifs_calc_signature(). In
addition, there are a few cases where no rfc1002 length is passed so we
make sure there's one (iov_len == 4).

Signed-off-by: Paulo Alcantara <palcantara@suse.de>
Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/smb2transport.c

index 50592976dcb4aff5242748f437ede68d4f71b82b..1af46ca5a951f740e4952fdbf049b8bf071c83b4 100644 (file)
@@ -408,12 +408,14 @@ generate_smb311signingkey(struct cifs_ses *ses)
 int
 smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
-       int rc = 0;
+       int rc;
        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[0].iov_base;
        struct cifs_ses *ses;
+       struct shash_desc *shash = &server->secmech.sdesccmacaes->shash;
+       struct smb_rqst drqst;
 
        ses = smb2_find_smb_ses(server, shdr->SessionId);
        if (!ses) {
@@ -425,8 +427,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 
        rc = crypto_shash_setkey(server->secmech.cmacaes,
-               ses->smb3signingkey, SMB2_CMACAES_SIZE);
-
+                                ses->smb3signingkey, SMB2_CMACAES_SIZE);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
                return rc;
@@ -437,15 +438,33 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
         * so unlike smb2 case we do not have to check here if secmech are
         * initialized
         */
-       rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash);
+       rc = crypto_shash_init(shash);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
                return rc;
        }
 
-       rc = __cifs_calc_signature(rqst, server, sigptr,
-                                  &server->secmech.sdesccmacaes->shash);
+       /*
+        * For SMB2+, __cifs_calc_signature() expects to sign only the actual
+        * data, that is, iov[0] should not contain a rfc1002 length.
+        *
+        * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to
+        * __cifs_calc_signature().
+        */
+       drqst = *rqst;
+       if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) {
+               rc = crypto_shash_update(shash, iov[0].iov_base,
+                                        iov[0].iov_len);
+               if (rc) {
+                       cifs_dbg(VFS, "%s: Could not update with payload\n",
+                                __func__);
+                       return rc;
+               }
+               drqst.rq_iov++;
+               drqst.rq_nvec--;
+       }
 
+       rc = __cifs_calc_signature(&drqst, server, sigptr, shash);
        if (!rc)
                memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);