Commit 1cb328da authored by Akhil R's avatar Akhil R Committed by Herbert Xu
Browse files

crypto: tegra - Do not use fixed size buffers



Allocate the buffer based on the request instead of a fixed buffer
length. In operations which may require larger buffer size, a fixed
buffer may fail.

Fixes: 0880bb3b ("crypto: tegra - Add Tegra Security Engine driver")
Signed-off-by: default avatarAkhil R <akhilrajeev@nvidia.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent bcfc8fc5
Loading
Loading
Loading
Loading
+64 −60
Original line number Diff line number Diff line
@@ -263,12 +263,6 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq)
	unsigned int cmdlen;
	int ret;

	rctx->datbuf.buf = dma_alloc_coherent(se->dev, SE_AES_BUFLEN,
					      &rctx->datbuf.addr, GFP_KERNEL);
	if (!rctx->datbuf.buf)
		return -ENOMEM;

	rctx->datbuf.size = SE_AES_BUFLEN;
	rctx->iv = (u32 *)req->iv;
	rctx->len = req->cryptlen;

@@ -278,6 +272,12 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq)
			rctx->len += AES_BLOCK_SIZE - (rctx->len % AES_BLOCK_SIZE);
	}

	rctx->datbuf.size = rctx->len;
	rctx->datbuf.buf = dma_alloc_coherent(se->dev, rctx->datbuf.size,
					      &rctx->datbuf.addr, GFP_KERNEL);
	if (!rctx->datbuf.buf)
		return -ENOMEM;

	scatterwalk_map_and_copy(rctx->datbuf.buf, req->src, 0, req->cryptlen, 0);

	/* Prepare the command and submit for execution */
@@ -289,7 +289,7 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq)
	scatterwalk_map_and_copy(rctx->datbuf.buf, req->dst, 0, req->cryptlen, 1);

	/* Free the buffer */
	dma_free_coherent(ctx->se->dev, SE_AES_BUFLEN,
	dma_free_coherent(ctx->se->dev, rctx->datbuf.size,
			  rctx->datbuf.buf, rctx->datbuf.addr);

	crypto_finalize_skcipher_request(se->engine, req, ret);
@@ -1117,6 +1117,11 @@ static int tegra_ccm_crypt_init(struct aead_request *req, struct tegra_se *se,
	rctx->assoclen = req->assoclen;
	rctx->authsize = crypto_aead_authsize(tfm);

	if (rctx->encrypt)
		rctx->cryptlen = req->cryptlen;
	else
		rctx->cryptlen = req->cryptlen - rctx->authsize;

	memcpy(iv, req->iv, 16);

	ret = tegra_ccm_check_iv(iv);
@@ -1145,30 +1150,26 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq)
	struct tegra_se *se = ctx->se;
	int ret;

	ret = tegra_ccm_crypt_init(req, se, rctx);
	if (ret)
		return ret;

	/* Allocate buffers required */
	rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, SE_AES_BUFLEN,
	rctx->inbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen + 100;
	rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->inbuf.size,
					     &rctx->inbuf.addr, GFP_KERNEL);
	if (!rctx->inbuf.buf)
		return -ENOMEM;

	rctx->inbuf.size = SE_AES_BUFLEN;

	rctx->outbuf.buf = dma_alloc_coherent(ctx->se->dev, SE_AES_BUFLEN,
	rctx->outbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen + 100;
	rctx->outbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->outbuf.size,
					      &rctx->outbuf.addr, GFP_KERNEL);
	if (!rctx->outbuf.buf) {
		ret = -ENOMEM;
		goto outbuf_err;
	}

	rctx->outbuf.size = SE_AES_BUFLEN;

	ret = tegra_ccm_crypt_init(req, se, rctx);
	if (ret)
		goto out;

	if (rctx->encrypt) {
		rctx->cryptlen = req->cryptlen;

		/* CBC MAC Operation */
		ret = tegra_ccm_compute_auth(ctx, rctx);
		if (ret)
@@ -1179,8 +1180,6 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq)
		if (ret)
			goto out;
	} else {
		rctx->cryptlen = req->cryptlen - ctx->authsize;

		/* CTR operation */
		ret = tegra_ccm_do_ctr(ctx, rctx);
		if (ret)
@@ -1193,11 +1192,11 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq)
	}

out:
	dma_free_coherent(ctx->se->dev, SE_AES_BUFLEN,
	dma_free_coherent(ctx->se->dev, rctx->inbuf.size,
			  rctx->outbuf.buf, rctx->outbuf.addr);

outbuf_err:
	dma_free_coherent(ctx->se->dev, SE_AES_BUFLEN,
	dma_free_coherent(ctx->se->dev, rctx->outbuf.size,
			  rctx->inbuf.buf, rctx->inbuf.addr);

	crypto_finalize_aead_request(ctx->se->engine, req, ret);
@@ -1213,23 +1212,6 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq)
	struct tegra_aead_reqctx *rctx = aead_request_ctx(req);
	int ret;

	/* Allocate buffers required */
	rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, SE_AES_BUFLEN,
					     &rctx->inbuf.addr, GFP_KERNEL);
	if (!rctx->inbuf.buf)
		return -ENOMEM;

	rctx->inbuf.size = SE_AES_BUFLEN;

	rctx->outbuf.buf = dma_alloc_coherent(ctx->se->dev, SE_AES_BUFLEN,
					      &rctx->outbuf.addr, GFP_KERNEL);
	if (!rctx->outbuf.buf) {
		ret = -ENOMEM;
		goto outbuf_err;
	}

	rctx->outbuf.size = SE_AES_BUFLEN;

	rctx->src_sg = req->src;
	rctx->dst_sg = req->dst;
	rctx->assoclen = req->assoclen;
@@ -1243,6 +1225,21 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq)
	memcpy(rctx->iv, req->iv, GCM_AES_IV_SIZE);
	rctx->iv[3] = (1 << 24);

	/* Allocate buffers required */
	rctx->inbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen;
	rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->inbuf.size,
					     &rctx->inbuf.addr, GFP_KERNEL);
	if (!rctx->inbuf.buf)
		return -ENOMEM;

	rctx->outbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen;
	rctx->outbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->outbuf.size,
					      &rctx->outbuf.addr, GFP_KERNEL);
	if (!rctx->outbuf.buf) {
		ret = -ENOMEM;
		goto outbuf_err;
	}

	/* If there is associated data perform GMAC operation */
	if (rctx->assoclen) {
		ret = tegra_gcm_do_gmac(ctx, rctx);
@@ -1266,11 +1263,11 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq)
		ret = tegra_gcm_do_verify(ctx->se, rctx);

out:
	dma_free_coherent(ctx->se->dev, SE_AES_BUFLEN,
	dma_free_coherent(ctx->se->dev, rctx->outbuf.size,
			  rctx->outbuf.buf, rctx->outbuf.addr);

outbuf_err:
	dma_free_coherent(ctx->se->dev, SE_AES_BUFLEN,
	dma_free_coherent(ctx->se->dev, rctx->inbuf.size,
			  rctx->inbuf.buf, rctx->inbuf.addr);

	/* Finalize the request if there are no errors */
@@ -1497,6 +1494,11 @@ static int tegra_cmac_do_update(struct ahash_request *req)
		return 0;
	}

	rctx->datbuf.buf = dma_alloc_coherent(se->dev, rctx->datbuf.size,
					      &rctx->datbuf.addr, GFP_KERNEL);
	if (!rctx->datbuf.buf)
		return -ENOMEM;

	/* Copy the previous residue first */
	if (rctx->residue.size)
		memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);
@@ -1529,6 +1531,9 @@ static int tegra_cmac_do_update(struct ahash_request *req)
	if (!(rctx->task & SHA_FINAL))
		tegra_cmac_copy_result(ctx->se, rctx);

	dma_free_coherent(ctx->se->dev, rctx->datbuf.size,
			  rctx->datbuf.buf, rctx->datbuf.addr);

	return ret;
}

@@ -1543,10 +1548,20 @@ static int tegra_cmac_do_final(struct ahash_request *req)

	if (!req->nbytes && !rctx->total_len && ctx->fallback_tfm) {
		return crypto_shash_tfm_digest(ctx->fallback_tfm,
					rctx->datbuf.buf, 0, req->result);
					NULL, 0, req->result);
	}

	if (rctx->residue.size) {
		rctx->datbuf.buf = dma_alloc_coherent(se->dev, rctx->residue.size,
						      &rctx->datbuf.addr, GFP_KERNEL);
		if (!rctx->datbuf.buf) {
			ret = -ENOMEM;
			goto out_free;
		}

		memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);
	}

	rctx->datbuf.size = rctx->residue.size;
	rctx->total_len += rctx->residue.size;
	rctx->config = tegra234_aes_cfg(SE_ALG_CMAC, 0);
@@ -1565,8 +1580,10 @@ static int tegra_cmac_do_final(struct ahash_request *req)
		writel(0, se->base + se->hw->regs->result + (i * 4));

out:
	dma_free_coherent(se->dev, SE_SHA_BUFLEN,
	if (rctx->residue.size)
		dma_free_coherent(se->dev, rctx->datbuf.size,
				  rctx->datbuf.buf, rctx->datbuf.addr);
out_free:
	dma_free_coherent(se->dev, crypto_ahash_blocksize(tfm) * 2,
			  rctx->residue.buf, rctx->residue.addr);
	return ret;
@@ -1672,28 +1689,15 @@ static int tegra_cmac_init(struct ahash_request *req)
	rctx->residue.buf = dma_alloc_coherent(se->dev, rctx->blk_size * 2,
					       &rctx->residue.addr, GFP_KERNEL);
	if (!rctx->residue.buf)
		goto resbuf_fail;
		return -ENOMEM;

	rctx->residue.size = 0;

	rctx->datbuf.buf = dma_alloc_coherent(se->dev, SE_SHA_BUFLEN,
					      &rctx->datbuf.addr, GFP_KERNEL);
	if (!rctx->datbuf.buf)
		goto datbuf_fail;

	rctx->datbuf.size = 0;

	/* Clear any previous result */
	for (i = 0; i < CMAC_RESULT_REG_COUNT; i++)
		writel(0, se->base + se->hw->regs->result + (i * 4));

	return 0;

datbuf_fail:
	dma_free_coherent(se->dev, rctx->blk_size, rctx->residue.buf,
			  rctx->residue.addr);
resbuf_fail:
	return -ENOMEM;
}

static int tegra_cmac_setkey(struct crypto_ahash *tfm, const u8 *key,
+25 −13
Original line number Diff line number Diff line
@@ -332,6 +332,11 @@ static int tegra_sha_do_update(struct ahash_request *req)
		return 0;
	}

	rctx->datbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->datbuf.size,
					      &rctx->datbuf.addr, GFP_KERNEL);
	if (!rctx->datbuf.buf)
		return -ENOMEM;

	/* Copy the previous residue first */
	if (rctx->residue.size)
		memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);
@@ -368,6 +373,9 @@ static int tegra_sha_do_update(struct ahash_request *req)
	if (!(rctx->task & SHA_FINAL))
		tegra_sha_copy_hash_result(se, rctx);

	dma_free_coherent(ctx->se->dev, rctx->datbuf.size,
			  rctx->datbuf.buf, rctx->datbuf.addr);

	return ret;
}

@@ -380,7 +388,17 @@ static int tegra_sha_do_final(struct ahash_request *req)
	u32 *cpuvaddr = se->cmdbuf->addr;
	int size, ret = 0;

	if (rctx->residue.size) {
		rctx->datbuf.buf = dma_alloc_coherent(se->dev, rctx->residue.size,
						      &rctx->datbuf.addr, GFP_KERNEL);
		if (!rctx->datbuf.buf) {
			ret = -ENOMEM;
			goto out_free;
		}

		memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);
	}

	rctx->datbuf.size = rctx->residue.size;
	rctx->total_len += rctx->residue.size;

@@ -397,8 +415,10 @@ static int tegra_sha_do_final(struct ahash_request *req)
	memcpy(req->result, rctx->digest.buf, rctx->digest.size);

out:
	dma_free_coherent(se->dev, SE_SHA_BUFLEN,
	if (rctx->residue.size)
		dma_free_coherent(se->dev, rctx->datbuf.size,
				  rctx->datbuf.buf, rctx->datbuf.addr);
out_free:
	dma_free_coherent(se->dev, crypto_ahash_blocksize(tfm),
			  rctx->residue.buf, rctx->residue.addr);
	dma_free_coherent(se->dev, rctx->digest.size, rctx->digest.buf,
@@ -527,19 +547,11 @@ static int tegra_sha_init(struct ahash_request *req)
	if (!rctx->residue.buf)
		goto resbuf_fail;

	rctx->datbuf.buf = dma_alloc_coherent(se->dev, SE_SHA_BUFLEN,
					      &rctx->datbuf.addr, GFP_KERNEL);
	if (!rctx->datbuf.buf)
		goto datbuf_fail;

	return 0;

datbuf_fail:
	dma_free_coherent(se->dev, rctx->blk_size, rctx->residue.buf,
			  rctx->residue.addr);
resbuf_fail:
	dma_free_coherent(se->dev, SE_SHA_BUFLEN, rctx->datbuf.buf,
			  rctx->datbuf.addr);
	dma_free_coherent(se->dev, rctx->digest.size, rctx->digest.buf,
			  rctx->digest.addr);
digbuf_fail:
	return -ENOMEM;
}
+0 −2
Original line number Diff line number Diff line
@@ -340,8 +340,6 @@
#define SE_CRYPTO_CTR_REG_COUNT			4
#define SE_MAX_KEYSLOT				15
#define SE_MAX_MEM_ALLOC			SZ_4M
#define SE_AES_BUFLEN				0x8000
#define SE_SHA_BUFLEN				0x2000

#define SHA_FIRST	BIT(0)
#define SHA_UPDATE	BIT(1)