diff mbox

[CIFS] Limit allocation of crypto mechanisms to when we need it for a particular dialect [version 2]

Message ID CAH2r5muf77vV9b4X+0U6Kv57XNPfxcCHAy7+hHtt_Fu96o+PzQ@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Steve French July 4, 2013, 4:57 a.m. UTC
Updated patch based on Jeff's feedback

From: Steve French <smfrench@gmail.com>
Date: Wed, 3 Jul 2013 23:52:11 -0500
Subject: [PATCH] [CIFS] Limit allocation of crypto mechanisms to dialect
 which requires it

Updated patch to try to prevent allocation of cifs, smb2 or smb3 crypto
secmech structures unless needed.  Currently cifs allocates all crypto
mechanisms when the first session is established (4 functions and
4 contexts), rather than only allocating these when needed (smb3 needs
two, the rest of the dialects only need one).

Signed-off-by: Steve French <smfrench@gmail.com>
---
 fs/cifs/cifsencrypt.c   | 195 +++++++++++++++++++++---------------------------
 fs/cifs/cifsproto.h     |   1 -
 fs/cifs/connect.c       |   6 --
 fs/cifs/smb2transport.c |  92 ++++++++++++++++++++++-
 4 files changed, 176 insertions(+), 118 deletions(-)

 	if (rc) {
@@ -61,7 +138,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct
TCP_Server_Info *server)

 	rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
 	if (rc) {
-		cifs_dbg(VFS, "%s: Could not init md5\n", __func__);
+		cifs_dbg(VFS, "%s: Could not init sha256", __func__);
 		return rc;
 	}

@@ -129,6 +206,14 @@ generate_smb3signingkey(struct TCP_Server_Info *server)
 	memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
 	memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);

+	/* SMB3 essentially requires signing so no harm making sure needed
+	   sechmech (hmacsha256 and aes) are allocated now */
+	rc = smb3_crypto_shash_allocate(server);
+	if (rc) {
+		cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
+		goto smb3signkey_ret;
+	}
+
 	rc = crypto_shash_setkey(server->secmech.hmacsha256,
 		server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
 	if (rc) {
@@ -210,6 +295,11 @@ smb3_calc_signature(struct smb_rqst *rqst, struct
TCP_Server_Info *server)
 		return rc;
 	}

+	/*
+	 * we already allocate sdesccmacaes when we init smb3 signing key,
+	 * so unlike smb2 case we do not have to check here if secmech are
+	 * initialized
+	 */
 	rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash);
 	if (rc) {
 		cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);

Comments

Shirish Pargaonkar July 4, 2013, 10:04 a.m. UTC | #1
On Wed, Jul 3, 2013 at 11:57 PM, Steve French <smfrench@gmail.com> wrote:
> Updated patch based on Jeff's feedback
>
> From: Steve French <smfrench@gmail.com>
> Date: Wed, 3 Jul 2013 23:52:11 -0500
> Subject: [PATCH] [CIFS] Limit allocation of crypto mechanisms to dialect
>  which requires it
>
> Updated patch to try to prevent allocation of cifs, smb2 or smb3 crypto
> secmech structures unless needed.  Currently cifs allocates all crypto
> mechanisms when the first session is established (4 functions and
> 4 contexts), rather than only allocating these when needed (smb3 needs
> two, the rest of the dialects only need one).
>
> Signed-off-by: Steve French <smfrench@gmail.com>
> ---
>  fs/cifs/cifsencrypt.c   | 195 +++++++++++++++++++++---------------------------
>  fs/cifs/cifsproto.h     |   1 -
>  fs/cifs/connect.c       |   6 --
>  fs/cifs/smb2transport.c |  92 ++++++++++++++++++++++-
>  4 files changed, 176 insertions(+), 118 deletions(-)
>
> diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
> index 3d8bf94..a95ee91 100644
> --- a/fs/cifs/cifsencrypt.c
> +++ b/fs/cifs/cifsencrypt.c
> @@ -1,7 +1,7 @@
>  /*
>   *   fs/cifs/cifsencrypt.c
>   *
> - *   Copyright (C) International Business Machines  Corp., 2005,2006
> + *   Copyright (C) International Business Machines  Corp., 2005,2013
>   *   Author(s): Steve French (sfrench@us.ibm.com)
>   *
>   *   This library is free software; you can redistribute it and/or modify
> @@ -31,6 +31,36 @@
>  #include <linux/random.h>
>  #include <linux/highmem.h>
>
> +static int
> +cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
> +{
> +       int rc;
> +       unsigned int size;
> +
> +       if (server->secmech.sdescmd5 != NULL)
> +               return 0; /* already allocated */
> +
> +       server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
> +       if (IS_ERR(server->secmech.md5)) {
> +               cifs_dbg(VFS, "could not allocate crypto md5\n");
> +               return PTR_ERR(server->secmech.md5);
> +       }
> +
> +       size = sizeof(struct shash_desc) +
> +                       crypto_shash_descsize(server->secmech.md5);
> +       server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
> +       if (!server->secmech.sdescmd5) {
> +               rc = -ENOMEM;
> +               crypto_free_shash(server->secmech.md5);
> +               server->secmech.md5 = NULL;
> +               return rc;
> +       }
> +       server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
> +       server->secmech.sdescmd5->shash.flags = 0x0;
> +
> +       return 0;
> +}
> +
>  /*
>   * Calculate and return the CIFS signature based on the mac key and SMB PDU.
>   * The 16 byte signature must be allocated by the caller. Note we only use the
> @@ -50,8 +80,11 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
>                 return -EINVAL;
>
>         if (!server->secmech.sdescmd5) {
> -               cifs_dbg(VFS, "%s: Can't generate signature\n", __func__);
> -               return -1;
> +               rc = cifs_crypto_shash_md5_allocate(server);
> +               if (rc) {
> +                       cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
> +                       return -1;
> +               }
>         }
>
>         rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
> @@ -556,6 +589,33 @@ CalcNTLMv2_response(const struct cifs_ses *ses,
> char *ntlmv2_hash)
>         return rc;
>  }
>
> +static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
> +{
> +       unsigned int size;
> +
> +       /* check if already allocated */
> +       if (server->secmech.sdeschmacmd5)
> +               return 0;
> +
> +       server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
> +       if (IS_ERR(server->secmech.hmacmd5)) {
> +               cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
> +               return PTR_ERR(server->secmech.hmacmd5);
> +       }
> +
> +       size = sizeof(struct shash_desc) +
> +                       crypto_shash_descsize(server->secmech.hmacmd5);
> +       server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
> +       if (!server->secmech.sdeschmacmd5) {
> +               crypto_free_shash(server->secmech.hmacmd5);
> +               server->secmech.hmacmd5 = NULL;
> +               return -ENOMEM;
> +       }
> +       server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
> +       server->secmech.sdeschmacmd5->shash.flags = 0x0;
> +
> +       return 0;
> +}
>
>  int
>  setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
> @@ -606,6 +666,12 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const
> struct nls_table *nls_cp)
>
>         memcpy(ses->auth_key.response + baselen, tiblob, tilen);
>
> +       rc = crypto_hmacmd5_alloc(ses->server);
> +       if (rc) {
> +               cifs_dbg(VFS, "could not crypto alloc md5 rc %d\n", rc);
> +               goto setup_ntlmv2_rsp_ret;
> +       }

This does not seem right.
1) The comment should be changed to state hmacmd5
2) We would fail ntlmv2/ntlmssp authentications for all subsequent
     sessions on this connection since hmac md5 crypto resource
     would have been allocated during first session.

> +
>         /* calculate ntlmv2_hash */
>         rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
>         if (rc) {
> @@ -705,123 +771,32 @@ calc_seckey(struct cifs_ses *ses)
>  void
>  cifs_crypto_shash_release(struct TCP_Server_Info *server)
>  {
> -       if (server->secmech.cmacaes)
> +       if (server->secmech.cmacaes) {
>                 crypto_free_shash(server->secmech.cmacaes);
> +               server->secmech.cmacaes = NULL;
> +       }
>
> -       if (server->secmech.hmacsha256)
> +       if (server->secmech.hmacsha256) {
>                 crypto_free_shash(server->secmech.hmacsha256);
> +               server->secmech.hmacsha256 = NULL;
> +       }
>
> -       if (server->secmech.md5)
> +       if (server->secmech.md5) {
>                 crypto_free_shash(server->secmech.md5);
> +               server->secmech.md5 = NULL;
> +       }
>
> -       if (server->secmech.hmacmd5)
> +       if (server->secmech.hmacmd5) {
>                 crypto_free_shash(server->secmech.hmacmd5);
> +               server->secmech.hmacmd5 = NULL;
> +       }
>
>         kfree(server->secmech.sdesccmacaes);
> -
> +       server->secmech.sdesccmacaes = NULL;
>         kfree(server->secmech.sdeschmacsha256);
> -
> +       server->secmech.sdeschmacsha256 = NULL;
>         kfree(server->secmech.sdeschmacmd5);
> -
> +       server->secmech.sdeschmacmd5 = NULL;
>         kfree(server->secmech.sdescmd5);
> -}
> -
> -int
> -cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
> -{
> -       int rc;
> -       unsigned int size;
> -
> -       server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
> -       if (IS_ERR(server->secmech.hmacmd5)) {
> -               cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
> -               return PTR_ERR(server->secmech.hmacmd5);
> -       }
> -
> -       server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
> -       if (IS_ERR(server->secmech.md5)) {
> -               cifs_dbg(VFS, "could not allocate crypto md5\n");
> -               rc = PTR_ERR(server->secmech.md5);
> -               goto crypto_allocate_md5_fail;
> -       }
> -
> -       server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
> -       if (IS_ERR(server->secmech.hmacsha256)) {
> -               cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
> -               rc = PTR_ERR(server->secmech.hmacsha256);
> -               goto crypto_allocate_hmacsha256_fail;
> -       }
> -
> -       server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
> -       if (IS_ERR(server->secmech.cmacaes)) {
> -               cifs_dbg(VFS, "could not allocate crypto cmac-aes");
> -               rc = PTR_ERR(server->secmech.cmacaes);
> -               goto crypto_allocate_cmacaes_fail;
> -       }
> -
> -       size = sizeof(struct shash_desc) +
> -                       crypto_shash_descsize(server->secmech.hmacmd5);
> -       server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
> -       if (!server->secmech.sdeschmacmd5) {
> -               rc = -ENOMEM;
> -               goto crypto_allocate_hmacmd5_sdesc_fail;
> -       }
> -       server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
> -       server->secmech.sdeschmacmd5->shash.flags = 0x0;
> -
> -       size = sizeof(struct shash_desc) +
> -                       crypto_shash_descsize(server->secmech.md5);
> -       server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
> -       if (!server->secmech.sdescmd5) {
> -               rc = -ENOMEM;
> -               goto crypto_allocate_md5_sdesc_fail;
> -       }
> -       server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
> -       server->secmech.sdescmd5->shash.flags = 0x0;
> -
> -       size = sizeof(struct shash_desc) +
> -                       crypto_shash_descsize(server->secmech.hmacsha256);
> -       server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
> -       if (!server->secmech.sdeschmacsha256) {
> -               rc = -ENOMEM;
> -               goto crypto_allocate_hmacsha256_sdesc_fail;
> -       }
> -       server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
> -       server->secmech.sdeschmacsha256->shash.flags = 0x0;
> -
> -       size = sizeof(struct shash_desc) +
> -                       crypto_shash_descsize(server->secmech.cmacaes);
> -       server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
> -       if (!server->secmech.sdesccmacaes) {
> -               cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
> -               rc = -ENOMEM;
> -               goto crypto_allocate_cmacaes_sdesc_fail;
> -       }
> -       server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
> -       server->secmech.sdesccmacaes->shash.flags = 0x0;
> -
> -       return 0;
> -
> -crypto_allocate_cmacaes_sdesc_fail:
> -       kfree(server->secmech.sdeschmacsha256);
> -
> -crypto_allocate_hmacsha256_sdesc_fail:
> -       kfree(server->secmech.sdescmd5);
> -
> -crypto_allocate_md5_sdesc_fail:
> -       kfree(server->secmech.sdeschmacmd5);
> -
> -crypto_allocate_hmacmd5_sdesc_fail:
> -       crypto_free_shash(server->secmech.cmacaes);
> -
> -crypto_allocate_cmacaes_fail:
> -       crypto_free_shash(server->secmech.hmacsha256);
> -
> -crypto_allocate_hmacsha256_fail:
> -       crypto_free_shash(server->secmech.md5);
> -
> -crypto_allocate_md5_fail:
> -       crypto_free_shash(server->secmech.hmacmd5);
> -
> -       return rc;
> +       server->secmech.sdescmd5 = NULL;
>  }
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index c8ff018..f7e584d 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -433,7 +433,6 @@ extern int SMBNTencrypt(unsigned char *, unsigned
> char *, unsigned char *,
>                         const struct nls_table *);
>  extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
>  extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
> -extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
>  extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
>  extern int calc_seckey(struct cifs_ses *);
>  extern void generate_smb3signingkey(struct TCP_Server_Info *);
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index afcb8a1..fa68813 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -2108,12 +2108,6 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
>                 goto out_err;
>         }
>
> -       rc = cifs_crypto_shash_allocate(tcp_ses);
> -       if (rc) {
> -               cifs_dbg(VFS, "could not setup hash structures rc %d\n", rc);
> -               goto out_err;
> -       }
> -
>         tcp_ses->ops = volume_info->ops;
>         tcp_ses->vals = volume_info->vals;
>         cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
> diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
> index 09b4fba..aef8ff4 100644
> --- a/fs/cifs/smb2transport.c
> +++ b/fs/cifs/smb2transport.c
> @@ -39,6 +39,77 @@
>  #include "smb2status.h"
>  #include "smb2glob.h"
>
> +static int
> +smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
> +{
> +       unsigned int size;
> +
> +       if (server->secmech.sdeschmacsha256 != NULL)
> +               return 0; /* already allocated */
> +
> +       server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
> +       if (IS_ERR(server->secmech.hmacsha256)) {
> +               cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
> +               return PTR_ERR(server->secmech.hmacsha256);
> +       }
> +
> +       size = sizeof(struct shash_desc) +
> +                       crypto_shash_descsize(server->secmech.hmacsha256);
> +       server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
> +       if (!server->secmech.sdeschmacsha256) {
> +               crypto_free_shash(server->secmech.hmacsha256);
> +               server->secmech.hmacsha256 = NULL;
> +               return -ENOMEM;
> +       }
> +       server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
> +       server->secmech.sdeschmacsha256->shash.flags = 0x0;
> +
> +       return 0;
> +}
> +
> +static int
> +smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
> +{
> +       unsigned int size;
> +       int rc;
> +
> +       if (server->secmech.sdesccmacaes != NULL)
> +               return 0;  /* already allocated */
> +
> +       rc = smb2_crypto_shash_allocate(server);
> +       if (rc)
> +               return rc;
> +
> +       server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
> +       if (IS_ERR(server->secmech.cmacaes)) {
> +               cifs_dbg(VFS, "could not allocate crypto cmac-aes");
> +               kfree(server->secmech.sdeschmacsha256);
> +               server->secmech.sdeschmacsha256 = NULL;
> +               crypto_free_shash(server->secmech.hmacsha256);
> +               server->secmech.hmacsha256 = NULL;
> +               return PTR_ERR(server->secmech.cmacaes);
> +       }
> +
> +       size = sizeof(struct shash_desc) +
> +                       crypto_shash_descsize(server->secmech.cmacaes);
> +       server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
> +       if (!server->secmech.sdesccmacaes) {
> +               cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
> +               kfree(server->secmech.sdeschmacsha256);
> +               server->secmech.sdeschmacsha256 = NULL;
> +               crypto_free_shash(server->secmech.hmacsha256);
> +               crypto_free_shash(server->secmech.cmacaes);
> +               server->secmech.hmacsha256 = NULL;
> +               server->secmech.cmacaes = NULL;
> +               return -ENOMEM;
> +       }
> +       server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
> +       server->secmech.sdesccmacaes->shash.flags = 0x0;
> +
> +       return 0;
> +}
> +
> +
>  int
>  smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
>  {
> @@ -52,6 +123,12 @@ smb2_calc_signature(struct smb_rqst *rqst, struct
> TCP_Server_Info *server)
>         memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
>         memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
>
> +       rc = smb2_crypto_shash_allocate(server);
> +       if (rc) {
> +               cifs_dbg(VFS, "%s: shah256 alloc failed\n", __func__);
> +               return rc;
> +       }
> +
>         rc = crypto_shash_setkey(server->secmech.hmacsha256,
>                 server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
>         if (rc) {
> @@ -61,7 +138,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct
> TCP_Server_Info *server)
>
>         rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
>         if (rc) {
> -               cifs_dbg(VFS, "%s: Could not init md5\n", __func__);
> +               cifs_dbg(VFS, "%s: Could not init sha256", __func__);
>                 return rc;
>         }
>
> @@ -129,6 +206,14 @@ generate_smb3signingkey(struct TCP_Server_Info *server)
>         memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
>         memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);
>
> +       /* SMB3 essentially requires signing so no harm making sure needed
> +          sechmech (hmacsha256 and aes) are allocated now */
> +       rc = smb3_crypto_shash_allocate(server);
> +       if (rc) {
> +               cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
> +               goto smb3signkey_ret;
> +       }
> +
>         rc = crypto_shash_setkey(server->secmech.hmacsha256,
>                 server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
>         if (rc) {
> @@ -210,6 +295,11 @@ smb3_calc_signature(struct smb_rqst *rqst, struct
> TCP_Server_Info *server)
>                 return rc;
>         }
>
> +       /*
> +        * we already allocate sdesccmacaes when we init smb3 signing key,
> +        * so unlike smb2 case we do not have to check here if secmech are
> +        * initialized
> +        */
>         rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash);
>         if (rc) {
>                 cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
> --
> 1.7.11.7
>
>
> --
> Thanks,
>
> Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Shirish Pargaonkar July 4, 2013, 10:14 a.m. UTC | #2
Sorry, ignore my point 2), was not thinking properly...

On Thu, Jul 4, 2013 at 5:04 AM, Shirish Pargaonkar
<shirishpargaonkar@gmail.com> wrote:
> On Wed, Jul 3, 2013 at 11:57 PM, Steve French <smfrench@gmail.com> wrote:
>> Updated patch based on Jeff's feedback
>>
>> From: Steve French <smfrench@gmail.com>
>> Date: Wed, 3 Jul 2013 23:52:11 -0500
>> Subject: [PATCH] [CIFS] Limit allocation of crypto mechanisms to dialect
>>  which requires it
>>
>> Updated patch to try to prevent allocation of cifs, smb2 or smb3 crypto
>> secmech structures unless needed.  Currently cifs allocates all crypto
>> mechanisms when the first session is established (4 functions and
>> 4 contexts), rather than only allocating these when needed (smb3 needs
>> two, the rest of the dialects only need one).
>>
>> Signed-off-by: Steve French <smfrench@gmail.com>
>> ---
>>  fs/cifs/cifsencrypt.c   | 195 +++++++++++++++++++++---------------------------
>>  fs/cifs/cifsproto.h     |   1 -
>>  fs/cifs/connect.c       |   6 --
>>  fs/cifs/smb2transport.c |  92 ++++++++++++++++++++++-
>>  4 files changed, 176 insertions(+), 118 deletions(-)
>>
>> diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
>> index 3d8bf94..a95ee91 100644
>> --- a/fs/cifs/cifsencrypt.c
>> +++ b/fs/cifs/cifsencrypt.c
>> @@ -1,7 +1,7 @@
>>  /*
>>   *   fs/cifs/cifsencrypt.c
>>   *
>> - *   Copyright (C) International Business Machines  Corp., 2005,2006
>> + *   Copyright (C) International Business Machines  Corp., 2005,2013
>>   *   Author(s): Steve French (sfrench@us.ibm.com)
>>   *
>>   *   This library is free software; you can redistribute it and/or modify
>> @@ -31,6 +31,36 @@
>>  #include <linux/random.h>
>>  #include <linux/highmem.h>
>>
>> +static int
>> +cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
>> +{
>> +       int rc;
>> +       unsigned int size;
>> +
>> +       if (server->secmech.sdescmd5 != NULL)
>> +               return 0; /* already allocated */
>> +
>> +       server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
>> +       if (IS_ERR(server->secmech.md5)) {
>> +               cifs_dbg(VFS, "could not allocate crypto md5\n");
>> +               return PTR_ERR(server->secmech.md5);
>> +       }
>> +
>> +       size = sizeof(struct shash_desc) +
>> +                       crypto_shash_descsize(server->secmech.md5);
>> +       server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
>> +       if (!server->secmech.sdescmd5) {
>> +               rc = -ENOMEM;
>> +               crypto_free_shash(server->secmech.md5);
>> +               server->secmech.md5 = NULL;
>> +               return rc;
>> +       }
>> +       server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
>> +       server->secmech.sdescmd5->shash.flags = 0x0;
>> +
>> +       return 0;
>> +}
>> +
>>  /*
>>   * Calculate and return the CIFS signature based on the mac key and SMB PDU.
>>   * The 16 byte signature must be allocated by the caller. Note we only use the
>> @@ -50,8 +80,11 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
>>                 return -EINVAL;
>>
>>         if (!server->secmech.sdescmd5) {
>> -               cifs_dbg(VFS, "%s: Can't generate signature\n", __func__);
>> -               return -1;
>> +               rc = cifs_crypto_shash_md5_allocate(server);
>> +               if (rc) {
>> +                       cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
>> +                       return -1;
>> +               }
>>         }
>>
>>         rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
>> @@ -556,6 +589,33 @@ CalcNTLMv2_response(const struct cifs_ses *ses,
>> char *ntlmv2_hash)
>>         return rc;
>>  }
>>
>> +static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
>> +{
>> +       unsigned int size;
>> +
>> +       /* check if already allocated */
>> +       if (server->secmech.sdeschmacmd5)
>> +               return 0;
>> +
>> +       server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
>> +       if (IS_ERR(server->secmech.hmacmd5)) {
>> +               cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
>> +               return PTR_ERR(server->secmech.hmacmd5);
>> +       }
>> +
>> +       size = sizeof(struct shash_desc) +
>> +                       crypto_shash_descsize(server->secmech.hmacmd5);
>> +       server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
>> +       if (!server->secmech.sdeschmacmd5) {
>> +               crypto_free_shash(server->secmech.hmacmd5);
>> +               server->secmech.hmacmd5 = NULL;
>> +               return -ENOMEM;
>> +       }
>> +       server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
>> +       server->secmech.sdeschmacmd5->shash.flags = 0x0;
>> +
>> +       return 0;
>> +}
>>
>>  int
>>  setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
>> @@ -606,6 +666,12 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const
>> struct nls_table *nls_cp)
>>
>>         memcpy(ses->auth_key.response + baselen, tiblob, tilen);
>>
>> +       rc = crypto_hmacmd5_alloc(ses->server);
>> +       if (rc) {
>> +               cifs_dbg(VFS, "could not crypto alloc md5 rc %d\n", rc);
>> +               goto setup_ntlmv2_rsp_ret;
>> +       }
>
> This does not seem right.
> 1) The comment should be changed to state hmacmd5
> 2) We would fail ntlmv2/ntlmssp authentications for all subsequent
>      sessions on this connection since hmac md5 crypto resource
>      would have been allocated during first session.
>
>> +
>>         /* calculate ntlmv2_hash */
>>         rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
>>         if (rc) {
>> @@ -705,123 +771,32 @@ calc_seckey(struct cifs_ses *ses)
>>  void
>>  cifs_crypto_shash_release(struct TCP_Server_Info *server)
>>  {
>> -       if (server->secmech.cmacaes)
>> +       if (server->secmech.cmacaes) {
>>                 crypto_free_shash(server->secmech.cmacaes);
>> +               server->secmech.cmacaes = NULL;
>> +       }
>>
>> -       if (server->secmech.hmacsha256)
>> +       if (server->secmech.hmacsha256) {
>>                 crypto_free_shash(server->secmech.hmacsha256);
>> +               server->secmech.hmacsha256 = NULL;
>> +       }
>>
>> -       if (server->secmech.md5)
>> +       if (server->secmech.md5) {
>>                 crypto_free_shash(server->secmech.md5);
>> +               server->secmech.md5 = NULL;
>> +       }
>>
>> -       if (server->secmech.hmacmd5)
>> +       if (server->secmech.hmacmd5) {
>>                 crypto_free_shash(server->secmech.hmacmd5);
>> +               server->secmech.hmacmd5 = NULL;
>> +       }
>>
>>         kfree(server->secmech.sdesccmacaes);
>> -
>> +       server->secmech.sdesccmacaes = NULL;
>>         kfree(server->secmech.sdeschmacsha256);
>> -
>> +       server->secmech.sdeschmacsha256 = NULL;
>>         kfree(server->secmech.sdeschmacmd5);
>> -
>> +       server->secmech.sdeschmacmd5 = NULL;
>>         kfree(server->secmech.sdescmd5);
>> -}
>> -
>> -int
>> -cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
>> -{
>> -       int rc;
>> -       unsigned int size;
>> -
>> -       server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
>> -       if (IS_ERR(server->secmech.hmacmd5)) {
>> -               cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
>> -               return PTR_ERR(server->secmech.hmacmd5);
>> -       }
>> -
>> -       server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
>> -       if (IS_ERR(server->secmech.md5)) {
>> -               cifs_dbg(VFS, "could not allocate crypto md5\n");
>> -               rc = PTR_ERR(server->secmech.md5);
>> -               goto crypto_allocate_md5_fail;
>> -       }
>> -
>> -       server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
>> -       if (IS_ERR(server->secmech.hmacsha256)) {
>> -               cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
>> -               rc = PTR_ERR(server->secmech.hmacsha256);
>> -               goto crypto_allocate_hmacsha256_fail;
>> -       }
>> -
>> -       server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
>> -       if (IS_ERR(server->secmech.cmacaes)) {
>> -               cifs_dbg(VFS, "could not allocate crypto cmac-aes");
>> -               rc = PTR_ERR(server->secmech.cmacaes);
>> -               goto crypto_allocate_cmacaes_fail;
>> -       }
>> -
>> -       size = sizeof(struct shash_desc) +
>> -                       crypto_shash_descsize(server->secmech.hmacmd5);
>> -       server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
>> -       if (!server->secmech.sdeschmacmd5) {
>> -               rc = -ENOMEM;
>> -               goto crypto_allocate_hmacmd5_sdesc_fail;
>> -       }
>> -       server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
>> -       server->secmech.sdeschmacmd5->shash.flags = 0x0;
>> -
>> -       size = sizeof(struct shash_desc) +
>> -                       crypto_shash_descsize(server->secmech.md5);
>> -       server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
>> -       if (!server->secmech.sdescmd5) {
>> -               rc = -ENOMEM;
>> -               goto crypto_allocate_md5_sdesc_fail;
>> -       }
>> -       server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
>> -       server->secmech.sdescmd5->shash.flags = 0x0;
>> -
>> -       size = sizeof(struct shash_desc) +
>> -                       crypto_shash_descsize(server->secmech.hmacsha256);
>> -       server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
>> -       if (!server->secmech.sdeschmacsha256) {
>> -               rc = -ENOMEM;
>> -               goto crypto_allocate_hmacsha256_sdesc_fail;
>> -       }
>> -       server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
>> -       server->secmech.sdeschmacsha256->shash.flags = 0x0;
>> -
>> -       size = sizeof(struct shash_desc) +
>> -                       crypto_shash_descsize(server->secmech.cmacaes);
>> -       server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
>> -       if (!server->secmech.sdesccmacaes) {
>> -               cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
>> -               rc = -ENOMEM;
>> -               goto crypto_allocate_cmacaes_sdesc_fail;
>> -       }
>> -       server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
>> -       server->secmech.sdesccmacaes->shash.flags = 0x0;
>> -
>> -       return 0;
>> -
>> -crypto_allocate_cmacaes_sdesc_fail:
>> -       kfree(server->secmech.sdeschmacsha256);
>> -
>> -crypto_allocate_hmacsha256_sdesc_fail:
>> -       kfree(server->secmech.sdescmd5);
>> -
>> -crypto_allocate_md5_sdesc_fail:
>> -       kfree(server->secmech.sdeschmacmd5);
>> -
>> -crypto_allocate_hmacmd5_sdesc_fail:
>> -       crypto_free_shash(server->secmech.cmacaes);
>> -
>> -crypto_allocate_cmacaes_fail:
>> -       crypto_free_shash(server->secmech.hmacsha256);
>> -
>> -crypto_allocate_hmacsha256_fail:
>> -       crypto_free_shash(server->secmech.md5);
>> -
>> -crypto_allocate_md5_fail:
>> -       crypto_free_shash(server->secmech.hmacmd5);
>> -
>> -       return rc;
>> +       server->secmech.sdescmd5 = NULL;
>>  }
>> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
>> index c8ff018..f7e584d 100644
>> --- a/fs/cifs/cifsproto.h
>> +++ b/fs/cifs/cifsproto.h
>> @@ -433,7 +433,6 @@ extern int SMBNTencrypt(unsigned char *, unsigned
>> char *, unsigned char *,
>>                         const struct nls_table *);
>>  extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
>>  extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
>> -extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
>>  extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
>>  extern int calc_seckey(struct cifs_ses *);
>>  extern void generate_smb3signingkey(struct TCP_Server_Info *);
>> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
>> index afcb8a1..fa68813 100644
>> --- a/fs/cifs/connect.c
>> +++ b/fs/cifs/connect.c
>> @@ -2108,12 +2108,6 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
>>                 goto out_err;
>>         }
>>
>> -       rc = cifs_crypto_shash_allocate(tcp_ses);
>> -       if (rc) {
>> -               cifs_dbg(VFS, "could not setup hash structures rc %d\n", rc);
>> -               goto out_err;
>> -       }
>> -
>>         tcp_ses->ops = volume_info->ops;
>>         tcp_ses->vals = volume_info->vals;
>>         cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
>> diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
>> index 09b4fba..aef8ff4 100644
>> --- a/fs/cifs/smb2transport.c
>> +++ b/fs/cifs/smb2transport.c
>> @@ -39,6 +39,77 @@
>>  #include "smb2status.h"
>>  #include "smb2glob.h"
>>
>> +static int
>> +smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
>> +{
>> +       unsigned int size;
>> +
>> +       if (server->secmech.sdeschmacsha256 != NULL)
>> +               return 0; /* already allocated */
>> +
>> +       server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
>> +       if (IS_ERR(server->secmech.hmacsha256)) {
>> +               cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
>> +               return PTR_ERR(server->secmech.hmacsha256);
>> +       }
>> +
>> +       size = sizeof(struct shash_desc) +
>> +                       crypto_shash_descsize(server->secmech.hmacsha256);
>> +       server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
>> +       if (!server->secmech.sdeschmacsha256) {
>> +               crypto_free_shash(server->secmech.hmacsha256);
>> +               server->secmech.hmacsha256 = NULL;
>> +               return -ENOMEM;
>> +       }
>> +       server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
>> +       server->secmech.sdeschmacsha256->shash.flags = 0x0;
>> +
>> +       return 0;
>> +}
>> +
>> +static int
>> +smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
>> +{
>> +       unsigned int size;
>> +       int rc;
>> +
>> +       if (server->secmech.sdesccmacaes != NULL)
>> +               return 0;  /* already allocated */
>> +
>> +       rc = smb2_crypto_shash_allocate(server);
>> +       if (rc)
>> +               return rc;
>> +
>> +       server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
>> +       if (IS_ERR(server->secmech.cmacaes)) {
>> +               cifs_dbg(VFS, "could not allocate crypto cmac-aes");
>> +               kfree(server->secmech.sdeschmacsha256);
>> +               server->secmech.sdeschmacsha256 = NULL;
>> +               crypto_free_shash(server->secmech.hmacsha256);
>> +               server->secmech.hmacsha256 = NULL;
>> +               return PTR_ERR(server->secmech.cmacaes);
>> +       }
>> +
>> +       size = sizeof(struct shash_desc) +
>> +                       crypto_shash_descsize(server->secmech.cmacaes);
>> +       server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
>> +       if (!server->secmech.sdesccmacaes) {
>> +               cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
>> +               kfree(server->secmech.sdeschmacsha256);
>> +               server->secmech.sdeschmacsha256 = NULL;
>> +               crypto_free_shash(server->secmech.hmacsha256);
>> +               crypto_free_shash(server->secmech.cmacaes);
>> +               server->secmech.hmacsha256 = NULL;
>> +               server->secmech.cmacaes = NULL;
>> +               return -ENOMEM;
>> +       }
>> +       server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
>> +       server->secmech.sdesccmacaes->shash.flags = 0x0;
>> +
>> +       return 0;
>> +}
>> +
>> +
>>  int
>>  smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
>>  {
>> @@ -52,6 +123,12 @@ smb2_calc_signature(struct smb_rqst *rqst, struct
>> TCP_Server_Info *server)
>>         memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
>>         memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
>>
>> +       rc = smb2_crypto_shash_allocate(server);
>> +       if (rc) {
>> +               cifs_dbg(VFS, "%s: shah256 alloc failed\n", __func__);
>> +               return rc;
>> +       }
>> +
>>         rc = crypto_shash_setkey(server->secmech.hmacsha256,
>>                 server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
>>         if (rc) {
>> @@ -61,7 +138,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct
>> TCP_Server_Info *server)
>>
>>         rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
>>         if (rc) {
>> -               cifs_dbg(VFS, "%s: Could not init md5\n", __func__);
>> +               cifs_dbg(VFS, "%s: Could not init sha256", __func__);
>>                 return rc;
>>         }
>>
>> @@ -129,6 +206,14 @@ generate_smb3signingkey(struct TCP_Server_Info *server)
>>         memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
>>         memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);
>>
>> +       /* SMB3 essentially requires signing so no harm making sure needed
>> +          sechmech (hmacsha256 and aes) are allocated now */
>> +       rc = smb3_crypto_shash_allocate(server);
>> +       if (rc) {
>> +               cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
>> +               goto smb3signkey_ret;
>> +       }
>> +
>>         rc = crypto_shash_setkey(server->secmech.hmacsha256,
>>                 server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
>>         if (rc) {
>> @@ -210,6 +295,11 @@ smb3_calc_signature(struct smb_rqst *rqst, struct
>> TCP_Server_Info *server)
>>                 return rc;
>>         }
>>
>> +       /*
>> +        * we already allocate sdesccmacaes when we init smb3 signing key,
>> +        * so unlike smb2 case we do not have to check here if secmech are
>> +        * initialized
>> +        */
>>         rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash);
>>         if (rc) {
>>                 cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
>> --
>> 1.7.11.7
>>
>>
>> --
>> Thanks,
>>
>> Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jeff Layton July 4, 2013, 10:39 a.m. UTC | #3
On Wed, 2013-07-03 at 23:57 -0500, Steve French wrote:
> Updated patch based on Jeff's feedback
> 
> From: Steve French <smfrench@gmail.com>
> Date: Wed, 3 Jul 2013 23:52:11 -0500
> Subject: [PATCH] [CIFS] Limit allocation of crypto mechanisms to dialect
>  which requires it
> 
> Updated patch to try to prevent allocation of cifs, smb2 or smb3 crypto
> secmech structures unless needed.  Currently cifs allocates all crypto
> mechanisms when the first session is established (4 functions and
> 4 contexts), rather than only allocating these when needed (smb3 needs
> two, the rest of the dialects only need one).
> 
> Signed-off-by: Steve French <smfrench@gmail.com>
> ---
>  fs/cifs/cifsencrypt.c   | 195 +++++++++++++++++++++---------------------------
>  fs/cifs/cifsproto.h     |   1 -
>  fs/cifs/connect.c       |   6 --
>  fs/cifs/smb2transport.c |  92 ++++++++++++++++++++++-
>  4 files changed, 176 insertions(+), 118 deletions(-)
> 

Nice work.

One very minor nit about a comment inline below. Other than that, you
can add:

Acked-by: Jeff Layton <jlayton@redhat.com>

> diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
> index 3d8bf94..a95ee91 100644
> --- a/fs/cifs/cifsencrypt.c
> +++ b/fs/cifs/cifsencrypt.c
> @@ -1,7 +1,7 @@
>  /*
>   *   fs/cifs/cifsencrypt.c
>   *
> - *   Copyright (C) International Business Machines  Corp., 2005,2006
> + *   Copyright (C) International Business Machines  Corp., 2005,2013
>   *   Author(s): Steve French (sfrench@us.ibm.com)
>   *
>   *   This library is free software; you can redistribute it and/or modify
> @@ -31,6 +31,36 @@
>  #include <linux/random.h>
>  #include <linux/highmem.h>
> 
> +static int
> +cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
> +{
> +	int rc;
> +	unsigned int size;
> +
> +	if (server->secmech.sdescmd5 != NULL)
> +		return 0; /* already allocated */
> +
> +	server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
> +	if (IS_ERR(server->secmech.md5)) {
> +		cifs_dbg(VFS, "could not allocate crypto md5\n");
> +		return PTR_ERR(server->secmech.md5);
> +	}
> +
> +	size = sizeof(struct shash_desc) +
> +			crypto_shash_descsize(server->secmech.md5);
> +	server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
> +	if (!server->secmech.sdescmd5) {
> +		rc = -ENOMEM;
> +		crypto_free_shash(server->secmech.md5);
> +		server->secmech.md5 = NULL;
> +		return rc;
> +	}
> +	server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
> +	server->secmech.sdescmd5->shash.flags = 0x0;
> +
> +	return 0;
> +}
> +
>  /*
>   * Calculate and return the CIFS signature based on the mac key and SMB PDU.
>   * The 16 byte signature must be allocated by the caller. Note we only use the
> @@ -50,8 +80,11 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
>  		return -EINVAL;
> 
>  	if (!server->secmech.sdescmd5) {
> -		cifs_dbg(VFS, "%s: Can't generate signature\n", __func__);
> -		return -1;
> +		rc = cifs_crypto_shash_md5_allocate(server);
> +		if (rc) {
> +			cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
> +			return -1;
> +		}
>  	}
> 
>  	rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
> @@ -556,6 +589,33 @@ CalcNTLMv2_response(const struct cifs_ses *ses,
> char *ntlmv2_hash)
>  	return rc;
>  }
> 
> +static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
> +{
> +	unsigned int size;
> +
> +	/* check if already allocated */
> +	if (server->secmech.sdeschmacmd5)
> +		return 0;
> +
> +	server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
> +	if (IS_ERR(server->secmech.hmacmd5)) {
> +		cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
> +		return PTR_ERR(server->secmech.hmacmd5);
> +	}
> +
> +	size = sizeof(struct shash_desc) +
> +			crypto_shash_descsize(server->secmech.hmacmd5);
> +	server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
> +	if (!server->secmech.sdeschmacmd5) {
> +		crypto_free_shash(server->secmech.hmacmd5);
> +		server->secmech.hmacmd5 = NULL;
> +		return -ENOMEM;
> +	}
> +	server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
> +	server->secmech.sdeschmacmd5->shash.flags = 0x0;
> +
> +	return 0;
> +}
> 
>  int
>  setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
> @@ -606,6 +666,12 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const
> struct nls_table *nls_cp)
> 
>  	memcpy(ses->auth_key.response + baselen, tiblob, tilen);
> 
> +	rc = crypto_hmacmd5_alloc(ses->server);
> +	if (rc) {
> +		cifs_dbg(VFS, "could not crypto alloc md5 rc %d\n", rc);
> +		goto setup_ntlmv2_rsp_ret;
> +	}
> +
>  	/* calculate ntlmv2_hash */
>  	rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
>  	if (rc) {
> @@ -705,123 +771,32 @@ calc_seckey(struct cifs_ses *ses)
>  void
>  cifs_crypto_shash_release(struct TCP_Server_Info *server)
>  {
> -	if (server->secmech.cmacaes)
> +	if (server->secmech.cmacaes) {
>  		crypto_free_shash(server->secmech.cmacaes);
> +		server->secmech.cmacaes = NULL;
> +	}
> 
> -	if (server->secmech.hmacsha256)
> +	if (server->secmech.hmacsha256) {
>  		crypto_free_shash(server->secmech.hmacsha256);
> +		server->secmech.hmacsha256 = NULL;
> +	}
> 
> -	if (server->secmech.md5)
> +	if (server->secmech.md5) {
>  		crypto_free_shash(server->secmech.md5);
> +		server->secmech.md5 = NULL;
> +	}
> 
> -	if (server->secmech.hmacmd5)
> +	if (server->secmech.hmacmd5) {
>  		crypto_free_shash(server->secmech.hmacmd5);
> +		server->secmech.hmacmd5 = NULL;
> +	}
> 
>  	kfree(server->secmech.sdesccmacaes);
> -
> +	server->secmech.sdesccmacaes = NULL;
>  	kfree(server->secmech.sdeschmacsha256);
> -
> +	server->secmech.sdeschmacsha256 = NULL;
>  	kfree(server->secmech.sdeschmacmd5);
> -
> +	server->secmech.sdeschmacmd5 = NULL;
>  	kfree(server->secmech.sdescmd5);
> -}
> -
> -int
> -cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
> -{
> -	int rc;
> -	unsigned int size;
> -
> -	server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
> -	if (IS_ERR(server->secmech.hmacmd5)) {
> -		cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
> -		return PTR_ERR(server->secmech.hmacmd5);
> -	}
> -
> -	server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
> -	if (IS_ERR(server->secmech.md5)) {
> -		cifs_dbg(VFS, "could not allocate crypto md5\n");
> -		rc = PTR_ERR(server->secmech.md5);
> -		goto crypto_allocate_md5_fail;
> -	}
> -
> -	server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
> -	if (IS_ERR(server->secmech.hmacsha256)) {
> -		cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
> -		rc = PTR_ERR(server->secmech.hmacsha256);
> -		goto crypto_allocate_hmacsha256_fail;
> -	}
> -
> -	server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
> -	if (IS_ERR(server->secmech.cmacaes)) {
> -		cifs_dbg(VFS, "could not allocate crypto cmac-aes");
> -		rc = PTR_ERR(server->secmech.cmacaes);
> -		goto crypto_allocate_cmacaes_fail;
> -	}
> -
> -	size = sizeof(struct shash_desc) +
> -			crypto_shash_descsize(server->secmech.hmacmd5);
> -	server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
> -	if (!server->secmech.sdeschmacmd5) {
> -		rc = -ENOMEM;
> -		goto crypto_allocate_hmacmd5_sdesc_fail;
> -	}
> -	server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
> -	server->secmech.sdeschmacmd5->shash.flags = 0x0;
> -
> -	size = sizeof(struct shash_desc) +
> -			crypto_shash_descsize(server->secmech.md5);
> -	server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
> -	if (!server->secmech.sdescmd5) {
> -		rc = -ENOMEM;
> -		goto crypto_allocate_md5_sdesc_fail;
> -	}
> -	server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
> -	server->secmech.sdescmd5->shash.flags = 0x0;
> -
> -	size = sizeof(struct shash_desc) +
> -			crypto_shash_descsize(server->secmech.hmacsha256);
> -	server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
> -	if (!server->secmech.sdeschmacsha256) {
> -		rc = -ENOMEM;
> -		goto crypto_allocate_hmacsha256_sdesc_fail;
> -	}
> -	server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
> -	server->secmech.sdeschmacsha256->shash.flags = 0x0;
> -
> -	size = sizeof(struct shash_desc) +
> -			crypto_shash_descsize(server->secmech.cmacaes);
> -	server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
> -	if (!server->secmech.sdesccmacaes) {
> -		cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
> -		rc = -ENOMEM;
> -		goto crypto_allocate_cmacaes_sdesc_fail;
> -	}
> -	server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
> -	server->secmech.sdesccmacaes->shash.flags = 0x0;
> -
> -	return 0;
> -
> -crypto_allocate_cmacaes_sdesc_fail:
> -	kfree(server->secmech.sdeschmacsha256);
> -
> -crypto_allocate_hmacsha256_sdesc_fail:
> -	kfree(server->secmech.sdescmd5);
> -
> -crypto_allocate_md5_sdesc_fail:
> -	kfree(server->secmech.sdeschmacmd5);
> -
> -crypto_allocate_hmacmd5_sdesc_fail:
> -	crypto_free_shash(server->secmech.cmacaes);
> -
> -crypto_allocate_cmacaes_fail:
> -	crypto_free_shash(server->secmech.hmacsha256);
> -
> -crypto_allocate_hmacsha256_fail:
> -	crypto_free_shash(server->secmech.md5);
> -
> -crypto_allocate_md5_fail:
> -	crypto_free_shash(server->secmech.hmacmd5);
> -
> -	return rc;
> +	server->secmech.sdescmd5 = NULL;
>  }
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index c8ff018..f7e584d 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -433,7 +433,6 @@ extern int SMBNTencrypt(unsigned char *, unsigned
> char *, unsigned char *,
>  			const struct nls_table *);
>  extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
>  extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
> -extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
>  extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
>  extern int calc_seckey(struct cifs_ses *);
>  extern void generate_smb3signingkey(struct TCP_Server_Info *);
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index afcb8a1..fa68813 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -2108,12 +2108,6 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
>  		goto out_err;
>  	}
> 
> -	rc = cifs_crypto_shash_allocate(tcp_ses);
> -	if (rc) {
> -		cifs_dbg(VFS, "could not setup hash structures rc %d\n", rc);
> -		goto out_err;
> -	}
> -
>  	tcp_ses->ops = volume_info->ops;
>  	tcp_ses->vals = volume_info->vals;
>  	cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
> diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
> index 09b4fba..aef8ff4 100644
> --- a/fs/cifs/smb2transport.c
> +++ b/fs/cifs/smb2transport.c
> @@ -39,6 +39,77 @@
>  #include "smb2status.h"
>  #include "smb2glob.h"
> 
> +static int
> +smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
> +{
> +	unsigned int size;
> +
> +	if (server->secmech.sdeschmacsha256 != NULL)
> +		return 0; /* already allocated */
> +
> +	server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
> +	if (IS_ERR(server->secmech.hmacsha256)) {
> +		cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
> +		return PTR_ERR(server->secmech.hmacsha256);
> +	}
> +
> +	size = sizeof(struct shash_desc) +
> +			crypto_shash_descsize(server->secmech.hmacsha256);
> +	server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
> +	if (!server->secmech.sdeschmacsha256) {
> +		crypto_free_shash(server->secmech.hmacsha256);
> +		server->secmech.hmacsha256 = NULL;
> +		return -ENOMEM;
> +	}
> +	server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
> +	server->secmech.sdeschmacsha256->shash.flags = 0x0;
> +
> +	return 0;
> +}
> +
> +static int
> +smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
> +{
> +	unsigned int size;
> +	int rc;
> +
> +	if (server->secmech.sdesccmacaes != NULL)
> +		return 0;  /* already allocated */
> +
> +	rc = smb2_crypto_shash_allocate(server);
> +	if (rc)
> +		return rc;
> +
> +	server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
> +	if (IS_ERR(server->secmech.cmacaes)) {
> +		cifs_dbg(VFS, "could not allocate crypto cmac-aes");
> +		kfree(server->secmech.sdeschmacsha256);
> +		server->secmech.sdeschmacsha256 = NULL;
> +		crypto_free_shash(server->secmech.hmacsha256);
> +		server->secmech.hmacsha256 = NULL;
> +		return PTR_ERR(server->secmech.cmacaes);
> +	}
> +
> +	size = sizeof(struct shash_desc) +
> +			crypto_shash_descsize(server->secmech.cmacaes);
> +	server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
> +	if (!server->secmech.sdesccmacaes) {
> +		cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
> +		kfree(server->secmech.sdeschmacsha256);
> +		server->secmech.sdeschmacsha256 = NULL;
> +		crypto_free_shash(server->secmech.hmacsha256);
> +		crypto_free_shash(server->secmech.cmacaes);
> +		server->secmech.hmacsha256 = NULL;
> +		server->secmech.cmacaes = NULL;
> +		return -ENOMEM;
> +	}
> +	server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
> +	server->secmech.sdesccmacaes->shash.flags = 0x0;
> +
> +	return 0;
> +}
> +
> +
>  int
>  smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
>  {
> @@ -52,6 +123,12 @@ smb2_calc_signature(struct smb_rqst *rqst, struct
> TCP_Server_Info *server)
>  	memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
>  	memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
> 
> +	rc = smb2_crypto_shash_allocate(server);
> +	if (rc) {
> +		cifs_dbg(VFS, "%s: shah256 alloc failed\n", __func__);
> +		return rc;
> +	}
> +
>  	rc = crypto_shash_setkey(server->secmech.hmacsha256,
>  		server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
>  	if (rc) {
> @@ -61,7 +138,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct
> TCP_Server_Info *server)
> 
>  	rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
>  	if (rc) {
> -		cifs_dbg(VFS, "%s: Could not init md5\n", __func__);
> +		cifs_dbg(VFS, "%s: Could not init sha256", __func__);
>  		return rc;
>  	}
> 
> @@ -129,6 +206,14 @@ generate_smb3signingkey(struct TCP_Server_Info *server)
>  	memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
>  	memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);
> 
> +	/* SMB3 essentially requires signing so no harm making sure needed
> +	   sechmech (hmacsha256 and aes) are allocated now */

This comment should probably be reformatted...

> +	rc = smb3_crypto_shash_allocate(server);
> +	if (rc) {
> +		cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
> +		goto smb3signkey_ret;
> +	}
> +
>  	rc = crypto_shash_setkey(server->secmech.hmacsha256,
>  		server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
>  	if (rc) {
> @@ -210,6 +295,11 @@ smb3_calc_signature(struct smb_rqst *rqst, struct
> TCP_Server_Info *server)
>  		return rc;
>  	}
> 
> +	/*
> +	 * we already allocate sdesccmacaes when we init smb3 signing key,
> +	 * so unlike smb2 case we do not have to check here if secmech are
> +	 * initialized
> +	 */
>  	rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash);
>  	if (rc) {
>  		cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
> -- 
> 1.7.11.7
> 
>
diff mbox

Patch

diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 3d8bf94..a95ee91 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -1,7 +1,7 @@ 
 /*
  *   fs/cifs/cifsencrypt.c
  *
- *   Copyright (C) International Business Machines  Corp., 2005,2006
+ *   Copyright (C) International Business Machines  Corp., 2005,2013
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -31,6 +31,36 @@ 
 #include <linux/random.h>
 #include <linux/highmem.h>

+static int
+cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
+{
+	int rc;
+	unsigned int size;
+
+	if (server->secmech.sdescmd5 != NULL)
+		return 0; /* already allocated */
+
+	server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
+	if (IS_ERR(server->secmech.md5)) {
+		cifs_dbg(VFS, "could not allocate crypto md5\n");
+		return PTR_ERR(server->secmech.md5);
+	}
+
+	size = sizeof(struct shash_desc) +
+			crypto_shash_descsize(server->secmech.md5);
+	server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
+	if (!server->secmech.sdescmd5) {
+		rc = -ENOMEM;
+		crypto_free_shash(server->secmech.md5);
+		server->secmech.md5 = NULL;
+		return rc;
+	}
+	server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
+	server->secmech.sdescmd5->shash.flags = 0x0;
+
+	return 0;
+}
+
 /*
  * Calculate and return the CIFS signature based on the mac key and SMB PDU.
  * The 16 byte signature must be allocated by the caller. Note we only use the
@@ -50,8 +80,11 @@  static int cifs_calc_signature(struct smb_rqst *rqst,
 		return -EINVAL;

 	if (!server->secmech.sdescmd5) {
-		cifs_dbg(VFS, "%s: Can't generate signature\n", __func__);
-		return -1;
+		rc = cifs_crypto_shash_md5_allocate(server);
+		if (rc) {
+			cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
+			return -1;
+		}
 	}

 	rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
@@ -556,6 +589,33 @@  CalcNTLMv2_response(const struct cifs_ses *ses,
char *ntlmv2_hash)
 	return rc;
 }

+static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
+{
+	unsigned int size;
+
+	/* check if already allocated */
+	if (server->secmech.sdeschmacmd5)
+		return 0;
+
+	server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
+	if (IS_ERR(server->secmech.hmacmd5)) {
+		cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
+		return PTR_ERR(server->secmech.hmacmd5);
+	}
+
+	size = sizeof(struct shash_desc) +
+			crypto_shash_descsize(server->secmech.hmacmd5);
+	server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
+	if (!server->secmech.sdeschmacmd5) {
+		crypto_free_shash(server->secmech.hmacmd5);
+		server->secmech.hmacmd5 = NULL;
+		return -ENOMEM;
+	}
+	server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
+	server->secmech.sdeschmacmd5->shash.flags = 0x0;
+
+	return 0;
+}

 int
 setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
@@ -606,6 +666,12 @@  setup_ntlmv2_rsp(struct cifs_ses *ses, const
struct nls_table *nls_cp)

 	memcpy(ses->auth_key.response + baselen, tiblob, tilen);

+	rc = crypto_hmacmd5_alloc(ses->server);
+	if (rc) {
+		cifs_dbg(VFS, "could not crypto alloc md5 rc %d\n", rc);
+		goto setup_ntlmv2_rsp_ret;
+	}
+
 	/* calculate ntlmv2_hash */
 	rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
 	if (rc) {
@@ -705,123 +771,32 @@  calc_seckey(struct cifs_ses *ses)
 void
 cifs_crypto_shash_release(struct TCP_Server_Info *server)
 {
-	if (server->secmech.cmacaes)
+	if (server->secmech.cmacaes) {
 		crypto_free_shash(server->secmech.cmacaes);
+		server->secmech.cmacaes = NULL;
+	}

-	if (server->secmech.hmacsha256)
+	if (server->secmech.hmacsha256) {
 		crypto_free_shash(server->secmech.hmacsha256);
+		server->secmech.hmacsha256 = NULL;
+	}

-	if (server->secmech.md5)
+	if (server->secmech.md5) {
 		crypto_free_shash(server->secmech.md5);
+		server->secmech.md5 = NULL;
+	}

-	if (server->secmech.hmacmd5)
+	if (server->secmech.hmacmd5) {
 		crypto_free_shash(server->secmech.hmacmd5);
+		server->secmech.hmacmd5 = NULL;
+	}

 	kfree(server->secmech.sdesccmacaes);
-
+	server->secmech.sdesccmacaes = NULL;
 	kfree(server->secmech.sdeschmacsha256);
-
+	server->secmech.sdeschmacsha256 = NULL;
 	kfree(server->secmech.sdeschmacmd5);
-
+	server->secmech.sdeschmacmd5 = NULL;
 	kfree(server->secmech.sdescmd5);
-}
-
-int
-cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
-{
-	int rc;
-	unsigned int size;
-
-	server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
-	if (IS_ERR(server->secmech.hmacmd5)) {
-		cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
-		return PTR_ERR(server->secmech.hmacmd5);
-	}
-
-	server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
-	if (IS_ERR(server->secmech.md5)) {
-		cifs_dbg(VFS, "could not allocate crypto md5\n");
-		rc = PTR_ERR(server->secmech.md5);
-		goto crypto_allocate_md5_fail;
-	}
-
-	server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
-	if (IS_ERR(server->secmech.hmacsha256)) {
-		cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
-		rc = PTR_ERR(server->secmech.hmacsha256);
-		goto crypto_allocate_hmacsha256_fail;
-	}
-
-	server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
-	if (IS_ERR(server->secmech.cmacaes)) {
-		cifs_dbg(VFS, "could not allocate crypto cmac-aes");
-		rc = PTR_ERR(server->secmech.cmacaes);
-		goto crypto_allocate_cmacaes_fail;
-	}
-
-	size = sizeof(struct shash_desc) +
-			crypto_shash_descsize(server->secmech.hmacmd5);
-	server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
-	if (!server->secmech.sdeschmacmd5) {
-		rc = -ENOMEM;
-		goto crypto_allocate_hmacmd5_sdesc_fail;
-	}
-	server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
-	server->secmech.sdeschmacmd5->shash.flags = 0x0;
-
-	size = sizeof(struct shash_desc) +
-			crypto_shash_descsize(server->secmech.md5);
-	server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
-	if (!server->secmech.sdescmd5) {
-		rc = -ENOMEM;
-		goto crypto_allocate_md5_sdesc_fail;
-	}
-	server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
-	server->secmech.sdescmd5->shash.flags = 0x0;
-
-	size = sizeof(struct shash_desc) +
-			crypto_shash_descsize(server->secmech.hmacsha256);
-	server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
-	if (!server->secmech.sdeschmacsha256) {
-		rc = -ENOMEM;
-		goto crypto_allocate_hmacsha256_sdesc_fail;
-	}
-	server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
-	server->secmech.sdeschmacsha256->shash.flags = 0x0;
-
-	size = sizeof(struct shash_desc) +
-			crypto_shash_descsize(server->secmech.cmacaes);
-	server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
-	if (!server->secmech.sdesccmacaes) {
-		cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
-		rc = -ENOMEM;
-		goto crypto_allocate_cmacaes_sdesc_fail;
-	}
-	server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
-	server->secmech.sdesccmacaes->shash.flags = 0x0;
-
-	return 0;
-
-crypto_allocate_cmacaes_sdesc_fail:
-	kfree(server->secmech.sdeschmacsha256);
-
-crypto_allocate_hmacsha256_sdesc_fail:
-	kfree(server->secmech.sdescmd5);
-
-crypto_allocate_md5_sdesc_fail:
-	kfree(server->secmech.sdeschmacmd5);
-
-crypto_allocate_hmacmd5_sdesc_fail:
-	crypto_free_shash(server->secmech.cmacaes);
-
-crypto_allocate_cmacaes_fail:
-	crypto_free_shash(server->secmech.hmacsha256);
-
-crypto_allocate_hmacsha256_fail:
-	crypto_free_shash(server->secmech.md5);
-
-crypto_allocate_md5_fail:
-	crypto_free_shash(server->secmech.hmacmd5);
-
-	return rc;
+	server->secmech.sdescmd5 = NULL;
 }
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index c8ff018..f7e584d 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -433,7 +433,6 @@  extern int SMBNTencrypt(unsigned char *, unsigned
char *, unsigned char *,
 			const struct nls_table *);
 extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
 extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
-extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
 extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
 extern int calc_seckey(struct cifs_ses *);
 extern void generate_smb3signingkey(struct TCP_Server_Info *);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index afcb8a1..fa68813 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2108,12 +2108,6 @@  cifs_get_tcp_session(struct smb_vol *volume_info)
 		goto out_err;
 	}

-	rc = cifs_crypto_shash_allocate(tcp_ses);
-	if (rc) {
-		cifs_dbg(VFS, "could not setup hash structures rc %d\n", rc);
-		goto out_err;
-	}
-
 	tcp_ses->ops = volume_info->ops;
 	tcp_ses->vals = volume_info->vals;
 	cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 09b4fba..aef8ff4 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -39,6 +39,77 @@ 
 #include "smb2status.h"
 #include "smb2glob.h"

+static int
+smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
+{
+	unsigned int size;
+
+	if (server->secmech.sdeschmacsha256 != NULL)
+		return 0; /* already allocated */
+
+	server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
+	if (IS_ERR(server->secmech.hmacsha256)) {
+		cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
+		return PTR_ERR(server->secmech.hmacsha256);
+	}
+
+	size = sizeof(struct shash_desc) +
+			crypto_shash_descsize(server->secmech.hmacsha256);
+	server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
+	if (!server->secmech.sdeschmacsha256) {
+		crypto_free_shash(server->secmech.hmacsha256);
+		server->secmech.hmacsha256 = NULL;
+		return -ENOMEM;
+	}
+	server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
+	server->secmech.sdeschmacsha256->shash.flags = 0x0;
+
+	return 0;
+}
+
+static int
+smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
+{
+	unsigned int size;
+	int rc;
+
+	if (server->secmech.sdesccmacaes != NULL)
+		return 0;  /* already allocated */
+
+	rc = smb2_crypto_shash_allocate(server);
+	if (rc)
+		return rc;
+
+	server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
+	if (IS_ERR(server->secmech.cmacaes)) {
+		cifs_dbg(VFS, "could not allocate crypto cmac-aes");
+		kfree(server->secmech.sdeschmacsha256);
+		server->secmech.sdeschmacsha256 = NULL;
+		crypto_free_shash(server->secmech.hmacsha256);
+		server->secmech.hmacsha256 = NULL;
+		return PTR_ERR(server->secmech.cmacaes);
+	}
+
+	size = sizeof(struct shash_desc) +
+			crypto_shash_descsize(server->secmech.cmacaes);
+	server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
+	if (!server->secmech.sdesccmacaes) {
+		cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
+		kfree(server->secmech.sdeschmacsha256);
+		server->secmech.sdeschmacsha256 = NULL;
+		crypto_free_shash(server->secmech.hmacsha256);
+		crypto_free_shash(server->secmech.cmacaes);
+		server->secmech.hmacsha256 = NULL;
+		server->secmech.cmacaes = NULL;
+		return -ENOMEM;
+	}
+	server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
+	server->secmech.sdesccmacaes->shash.flags = 0x0;
+
+	return 0;
+}
+
+
 int
 smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
@@ -52,6 +123,12 @@  smb2_calc_signature(struct smb_rqst *rqst, struct
TCP_Server_Info *server)
 	memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
 	memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);

+	rc = smb2_crypto_shash_allocate(server);
+	if (rc) {
+		cifs_dbg(VFS, "%s: shah256 alloc failed\n", __func__);
+		return rc;
+	}
+
 	rc = crypto_shash_setkey(server->secmech.hmacsha256,
 		server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);