cryptodev: avoid untrusted user pointers
Konduri Praveen [Tue, 1 Aug 2017 12:05:58 +0000 (17:05 +0530)]
add algo variable for avoid the usage of
user space pointers

Bug 200286426

Change-Id: I7e208b45ba11348e7b89a429d457ae51ac29bde0
Signed-off-by: Konduri Praveen <kondurip@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1530560
(cherry picked from commit b210c724aea24160a5fdcec5ee9b8f9c86c8540d)
Reviewed-on: https://git-master.nvidia.com/r/1649889
GVS: Gerrit_Virtual_Submit
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Winnie Hsu <whsu@nvidia.com>
Tested-by: Winnie Hsu <whsu@nvidia.com>

drivers/misc/tegra-cryptodev.c

index 3b89504..6e2f00e 100644 (file)
@@ -3,7 +3,7 @@
  *
  * crypto dev node for NVIDIA tegra aes hardware
  *
- * Copyright (c) 2010-2017, NVIDIA Corporation. All Rights Reserved.
+ * Copyright (c) 2010-2018, NVIDIA Corporation. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -49,8 +49,6 @@
 struct tegra_crypto_ctx {
        struct crypto_ablkcipher *aes_tfm[4]; /*ecb, cbc, ofb, ctr */
        struct crypto_ahash *rsa_tfm[4]; /* rsa512, rsa1024, rsa1536, rsa2048 */
-       struct crypto_ahash *sha_tfm[6]; /* sha1, sha224, sha256, sha384,
-                                               sha512, cmac */
        struct crypto_rng *rng;
        struct crypto_rng *rng_drbg;
        u8 seed[TEGRA_CRYPTO_RNG_SEED_SIZE];
@@ -393,38 +391,33 @@ static int tegra_crypto_sha(struct file *filp, struct tegra_crypto_ctx *ctx,
        struct crypto_ahash *tfm;
        struct scatterlist sg[1];
        char result[64];
+       char algo[64];
        struct ahash_request *req;
        struct tegra_crypto_completion sha_complete;
        void *hash_buff;
        unsigned long *xbuf[XBUFSIZE];
-       int ret = -ENOMEM, i;
-       char sha_algo[6][10] = {"sha1", "sha224", "sha256",
-                               "sha384", "sha512", "cmac(aes)"};
+       int ret = -ENOMEM;
 
        if (sha_req->plaintext_sz > PAGE_SIZE) {
                pr_err("alg:hash: invalid plaintext_sz for sha_req\n");
                return -EINVAL;
        }
 
-       tfm = crypto_alloc_ahash(sha_req->algo, 0, 0);
+       if (strncpy_from_user(algo, sha_req->algo, sizeof(algo)) < 0)
+               return -EFAULT;
+       algo[sizeof(algo) - 1] = '\0';
+
+       tfm = crypto_alloc_ahash(algo, 0, 0);
        if (IS_ERR(tfm)) {
                pr_err("alg:hash:Failed to load transform for %s:%ld\n",
-                       sha_req->algo, PTR_ERR(tfm));
+                       algo, PTR_ERR(tfm));
                goto out_alloc;
        }
 
-       for (i = 0; i < 6; i++) {
-               if (!strcmp(sha_req->algo, sha_algo[i])) {
-                       ctx->sha_tfm[i] = tfm;
-                       break;
-               }
-       }
-       filp->private_data = ctx;
-
        req = ahash_request_alloc(tfm, GFP_KERNEL);
        if (!req) {
                pr_err("alg:hash:Failed to allocate request for %s\n",
-                       sha_req->algo);
+                       algo);
                goto out_noreq;
        }
 
@@ -440,7 +433,14 @@ static int tegra_crypto_sha(struct file *filp, struct tegra_crypto_ctx *ctx,
 
        hash_buff = xbuf[0];
 
-       memcpy(hash_buff, sha_req->plaintext, sha_req->plaintext_sz);
+       ret = copy_from_user((void *)hash_buff,
+                               (void __user *)sha_req->plaintext,
+                               sha_req->plaintext_sz);
+       if (ret) {
+               ret = -EFAULT;
+               pr_err("%s: copy_from_user failed (%d)\n", __func__, ret);
+                       goto out;
+       }
        sg_init_one(&sg[0], hash_buff, sha_req->plaintext_sz);
 
        if (sha_req->keylen) {
@@ -449,7 +449,7 @@ static int tegra_crypto_sha(struct file *filp, struct tegra_crypto_ctx *ctx,
                                          sha_req->keylen);
                if (ret) {
                        pr_err("alg:hash:setkey failed on %s:ret=%d\n",
-                               sha_req->algo, ret);
+                               algo, ret);
 
                        goto out;
                }
@@ -460,21 +460,21 @@ static int tegra_crypto_sha(struct file *filp, struct tegra_crypto_ctx *ctx,
        ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_init(req));
        if (ret) {
                pr_err("alg: hash: init failed for %s: ret=%d\n",
-                       sha_req->algo, ret);
+                       algo, ret);
                goto out;
        }
 
        ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_update(req));
        if (ret) {
                pr_err("alg: hash: update failed for %s: ret=%d\n",
-                       sha_req->algo, ret);
+                       algo, ret);
                goto out;
        }
 
        ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_final(req));
        if (ret) {
                pr_err("alg: hash: final failed for %s: ret=%d\n",
-                       sha_req->algo, ret);
+                       algo, ret);
                goto out;
        }
 
@@ -483,7 +483,7 @@ static int tegra_crypto_sha(struct file *filp, struct tegra_crypto_ctx *ctx,
        if (ret) {
                ret = -EFAULT;
                pr_err("alg: hash: copy_to_user failed (%d) for %s\n",
-                               ret, sha_req->algo);
+                               ret, algo);
        }
 
 out: