Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b9c4edd authored by Radu Solea's avatar Radu Solea Committed by Greg Kroah-Hartman
Browse files

crypto: mxs-dcp - Fix AES issues



[ Upstream commit fadd7a6e616b89c7f4f7bfa7b824f290bab32c3c ]

The DCP driver does not obey cryptlen, when doing android CTS this
results in passing to hardware input stream lengths which are not
multiple of block size.

Add a check to prevent future erroneous stream lengths from reaching the
hardware and adjust the scatterlist walking code to obey cryptlen.

Also properly copy-out the IV for chaining.

Signed-off-by: default avatarRadu Solea <radu.solea@nxp.com>
Signed-off-by: default avatarFranck LENORMAND <franck.lenormand@nxp.com>
Signed-off-by: default avatarLeonard Crestez <leonard.crestez@nxp.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 70ecd045
Loading
Loading
Loading
Loading
+31 −2
Original line number Diff line number Diff line
@@ -225,6 +225,12 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
	dma_addr_t dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf,
					     DCP_BUF_SZ, DMA_FROM_DEVICE);

	if (actx->fill % AES_BLOCK_SIZE) {
		dev_err(sdcp->dev, "Invalid block size!\n");
		ret = -EINVAL;
		goto aes_done_run;
	}

	/* Fill in the DMA descriptor. */
	desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE |
		    MXS_DCP_CONTROL0_INTERRUPT |
@@ -254,6 +260,7 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,

	ret = mxs_dcp_start_dma(actx);

aes_done_run:
	dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128,
			 DMA_TO_DEVICE);
	dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
@@ -280,13 +287,15 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)

	uint8_t *out_tmp, *src_buf, *dst_buf = NULL;
	uint32_t dst_off = 0;
	uint32_t last_out_len = 0;

	uint8_t *key = sdcp->coh->aes_key;

	int ret = 0;
	int split = 0;
	unsigned int i, len, clen, rem = 0;
	unsigned int i, len, clen, rem = 0, tlen = 0;
	int init = 0;
	bool limit_hit = false;

	actx->fill = 0;

@@ -305,6 +314,11 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
	for_each_sg(req->src, src, nents, i) {
		src_buf = sg_virt(src);
		len = sg_dma_len(src);
		tlen += len;
		limit_hit = tlen > req->nbytes;

		if (limit_hit)
			len = req->nbytes - (tlen - len);

		do {
			if (actx->fill + len > out_off)
@@ -321,13 +335,15 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
			 * If we filled the buffer or this is the last SG,
			 * submit the buffer.
			 */
			if (actx->fill == out_off || sg_is_last(src)) {
			if (actx->fill == out_off || sg_is_last(src) ||
				limit_hit) {
				ret = mxs_dcp_run_aes(actx, req, init);
				if (ret)
					return ret;
				init = 0;

				out_tmp = out_buf;
				last_out_len = actx->fill;
				while (dst && actx->fill) {
					if (!split) {
						dst_buf = sg_virt(dst);
@@ -350,6 +366,19 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
				}
			}
		} while (len);

		if (limit_hit)
			break;
	}

	/* Copy the IV for CBC for chaining */
	if (!rctx->ecb) {
		if (rctx->enc)
			memcpy(req->info, out_buf+(last_out_len-AES_BLOCK_SIZE),
				AES_BLOCK_SIZE);
		else
			memcpy(req->info, in_buf+(last_out_len-AES_BLOCK_SIZE),
				AES_BLOCK_SIZE);
	}

	return ret;