]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
CIFS: refactor crypto shash/sdesc allocation&free
authorAurelien Aptel <aaptel@suse.com>
Fri, 16 Feb 2018 18:19:27 +0000 (19:19 +0100)
committerKhalid Elmously <khalid.elmously@canonical.com>
Wed, 6 Jun 2018 15:48:27 +0000 (11:48 -0400)
BugLink: http://bugs.launchpad.net/bugs/1773233
commit 82fb82be05585426405667dd5f0510aa953ba439 upstream.

shash and sdesc and always allocated and freed together.
* abstract this in new functions cifs_alloc_hash() and cifs_free_hash().
* make smb2/3 crypto allocation independent from each other.

Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Steve French <smfrench@gmail.com>
Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Acked-by: Khalid Elmously <khalid.elmously@canonical.com>
Acked-by: Brad Figg <brad.figg@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
fs/cifs/cifsencrypt.c
fs/cifs/cifsproto.h
fs/cifs/link.c
fs/cifs/misc.c
fs/cifs/smb2transport.c
fs/cifs/smbencrypt.c

index f2b0a7f124da94070b46249e722e136e0a82f635..478a145aa4d09292f1c22187df79f85b9862731b 100644 (file)
 #include <crypto/skcipher.h>
 #include <crypto/aead.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");
-               rc = PTR_ERR(server->secmech.md5);
-               server->secmech.md5 = NULL;
-               return rc;
-       }
-
-       size = sizeof(struct shash_desc) +
-                       crypto_shash_descsize(server->secmech.md5);
-       server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
-       if (!server->secmech.sdescmd5) {
-               crypto_free_shash(server->secmech.md5);
-               server->secmech.md5 = NULL;
-               return -ENOMEM;
-       }
-       server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
-       server->secmech.sdescmd5->shash.flags = 0x0;
-
-       return 0;
-}
-
 int __cifs_calc_signature(struct smb_rqst *rqst,
                        struct TCP_Server_Info *server, char *signature,
                        struct shash_desc *shash)
@@ -132,13 +101,10 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
        if (!rqst->rq_iov || !signature || !server)
                return -EINVAL;
 
-       if (!server->secmech.sdescmd5) {
-               rc = cifs_crypto_shash_md5_allocate(server);
-               if (rc) {
-                       cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
-                       return -1;
-               }
-       }
+       rc = cifs_alloc_hash("md5", &server->secmech.md5,
+                            &server->secmech.sdescmd5);
+       if (rc)
+               return -1;
 
        rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
        if (rc) {
@@ -663,37 +629,6 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
        return rc;
 }
 
-static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
-{
-       int rc;
-       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");
-               rc = PTR_ERR(server->secmech.hmacmd5);
-               server->secmech.hmacmd5 = NULL;
-               return rc;
-       }
-
-       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)
 {
@@ -757,9 +692,10 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
 
        mutex_lock(&ses->server->srv_mutex);
 
-       rc = crypto_hmacmd5_alloc(ses->server);
+       rc = cifs_alloc_hash("hmac(md5)",
+                            &ses->server->secmech.hmacmd5,
+                            &ses->server->secmech.sdeschmacmd5);
        if (rc) {
-               cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc);
                goto unlock;
        }
 
index 4143c9dec46398328aa4c78af849c6032a0edfd3..762d513a5087507ce4f0b362dec3840c32027d98 100644 (file)
@@ -538,4 +538,9 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
 struct cifs_aio_ctx *cifs_aio_ctx_alloc(void);
 void cifs_aio_ctx_release(struct kref *refcount);
 int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);
+
+int cifs_alloc_hash(const char *name, struct crypto_shash **shash,
+                   struct sdesc **sdesc);
+void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc);
+
 #endif                 /* _CIFSPROTO_H */
index 60b5a11ee11b3d778b7f6e4850a70ac5cd10f293..889a840172eb8840daa73268e2ec5523122c4307 100644 (file)
@@ -50,25 +50,12 @@ static int
 symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
 {
        int rc;
-       unsigned int size;
-       struct crypto_shash *md5;
-       struct sdesc *sdescmd5;
-
-       md5 = crypto_alloc_shash("md5", 0, 0);
-       if (IS_ERR(md5)) {
-               rc = PTR_ERR(md5);
-               cifs_dbg(VFS, "%s: Crypto md5 allocation error %d\n",
-                        __func__, rc);
-               return rc;
-       }
-       size = sizeof(struct shash_desc) + crypto_shash_descsize(md5);
-       sdescmd5 = kmalloc(size, GFP_KERNEL);
-       if (!sdescmd5) {
-               rc = -ENOMEM;
+       struct crypto_shash *md5 = NULL;
+       struct sdesc *sdescmd5 = NULL;
+
+       rc = cifs_alloc_hash("md5", &md5, &sdescmd5);
+       if (rc)
                goto symlink_hash_err;
-       }
-       sdescmd5->shash.tfm = md5;
-       sdescmd5->shash.flags = 0x0;
 
        rc = crypto_shash_init(&sdescmd5->shash);
        if (rc) {
@@ -85,9 +72,7 @@ symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
                cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
 
 symlink_hash_err:
-       crypto_free_shash(md5);
-       kfree(sdescmd5);
-
+       cifs_free_hash(&md5, &sdescmd5);
        return rc;
 }
 
index a0dbced4a45c35b01107e532ee6167425b13ddff..460084a8eac54077010c12dee60d12e7c35fc5b8 100644 (file)
@@ -848,3 +848,57 @@ setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw)
        iov_iter_bvec(&ctx->iter, ITER_BVEC | rw, ctx->bv, npages, ctx->len);
        return 0;
 }
+
+/**
+ * cifs_alloc_hash - allocate hash and hash context together
+ *
+ * The caller has to make sure @sdesc is initialized to either NULL or
+ * a valid context. Both can be freed via cifs_free_hash().
+ */
+int
+cifs_alloc_hash(const char *name,
+               struct crypto_shash **shash, struct sdesc **sdesc)
+{
+       int rc = 0;
+       size_t size;
+
+       if (*sdesc != NULL)
+               return 0;
+
+       *shash = crypto_alloc_shash(name, 0, 0);
+       if (IS_ERR(*shash)) {
+               cifs_dbg(VFS, "could not allocate crypto %s\n", name);
+               rc = PTR_ERR(*shash);
+               *shash = NULL;
+               *sdesc = NULL;
+               return rc;
+       }
+
+       size = sizeof(struct shash_desc) + crypto_shash_descsize(*shash);
+       *sdesc = kmalloc(size, GFP_KERNEL);
+       if (*sdesc == NULL) {
+               cifs_dbg(VFS, "no memory left to allocate crypto %s\n", name);
+               crypto_free_shash(*shash);
+               *shash = NULL;
+               return -ENOMEM;
+       }
+
+       (*sdesc)->shash.tfm = *shash;
+       (*sdesc)->shash.flags = 0x0;
+       return 0;
+}
+
+/**
+ * cifs_free_hash - free hash and hash context together
+ *
+ * Freeing a NULL hash or context is safe.
+ */
+void
+cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc)
+{
+       kfree(*sdesc);
+       *sdesc = NULL;
+       if (*shash)
+               crypto_free_shash(*shash);
+       *shash = NULL;
+}
index 99493946e2f9abcf02673bf685238b0313da4180..c3c271f557a0a13ab6aaa98e079ddf0e069542ab 100644 (file)
 static int
 smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
 {
-       int rc;
-       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");
-               rc = PTR_ERR(server->secmech.hmacsha256);
-               server->secmech.hmacsha256 = NULL;
-               return rc;
-       }
-
-       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;
+       return cifs_alloc_hash("hmac(sha256)",
+                              &server->secmech.hmacsha256,
+                              &server->secmech.sdeschmacsha256);
 }
 
 static int
 smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
 {
-       unsigned int size;
+       struct cifs_secmech *p = &server->secmech;
        int rc;
 
-       if (server->secmech.sdesccmacaes != NULL)
-               return 0;  /* already allocated */
-
-       rc = smb2_crypto_shash_allocate(server);
+       rc = cifs_alloc_hash("hmac(sha256)",
+                            &p->hmacsha256,
+                            &p->sdeschmacsha256);
        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;
-               rc = PTR_ERR(server->secmech.cmacaes);
-               server->secmech.cmacaes = NULL;
-               return rc;
-       }
+               goto err;
 
-       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;
+       rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes);
+       if (rc)
+               goto err;
 
        return 0;
+err:
+       cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256);
+       return rc;
 }
 
 static struct cifs_ses *
@@ -457,7 +412,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
                cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
                return rc;
        }
-       
+
        rc = __cifs_calc_signature(rqst, server, sigptr,
                                   &server->secmech.sdesccmacaes->shash);
 
index c12bffefa3c9b59b2290ecdb243ae308b08e7224..a0b80ac651a60a385738ff5dff8b9cfa01de2ce4 100644 (file)
@@ -121,25 +121,12 @@ int
 mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len)
 {
        int rc;
-       unsigned int size;
-       struct crypto_shash *md4;
-       struct sdesc *sdescmd4;
-
-       md4 = crypto_alloc_shash("md4", 0, 0);
-       if (IS_ERR(md4)) {
-               rc = PTR_ERR(md4);
-               cifs_dbg(VFS, "%s: Crypto md4 allocation error %d\n",
-                        __func__, rc);
-               return rc;
-       }
-       size = sizeof(struct shash_desc) + crypto_shash_descsize(md4);
-       sdescmd4 = kmalloc(size, GFP_KERNEL);
-       if (!sdescmd4) {
-               rc = -ENOMEM;
+       struct crypto_shash *md4 = NULL;
+       struct sdesc *sdescmd4 = NULL;
+
+       rc = cifs_alloc_hash("md4", &md4, &sdescmd4);
+       if (rc)
                goto mdfour_err;
-       }
-       sdescmd4->shash.tfm = md4;
-       sdescmd4->shash.flags = 0x0;
 
        rc = crypto_shash_init(&sdescmd4->shash);
        if (rc) {
@@ -156,9 +143,7 @@ mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len)
                cifs_dbg(VFS, "%s: Could not generate md4 hash\n", __func__);
 
 mdfour_err:
-       crypto_free_shash(md4);
-       kfree(sdescmd4);
-
+       cifs_free_hash(&md4, &sdescmd4);
        return rc;
 }