crypto: mxs-dcp - Fix AES issues

[ Upstream commit fadd7a6e61 ]

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: Radu Solea <radu.solea@nxp.com>
Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Radu Solea 2018-10-02 19:01:52 +00:00 committed by Greg Kroah-Hartman
parent 70ecd0459d
commit 6b9c4eddb3
1 changed files with 31 additions and 2 deletions

View File

@ -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, dma_addr_t dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf,
DCP_BUF_SZ, DMA_FROM_DEVICE); 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. */ /* Fill in the DMA descriptor. */
desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE | desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE |
MXS_DCP_CONTROL0_INTERRUPT | 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); ret = mxs_dcp_start_dma(actx);
aes_done_run:
dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128, dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128,
DMA_TO_DEVICE); DMA_TO_DEVICE);
dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, 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; uint8_t *out_tmp, *src_buf, *dst_buf = NULL;
uint32_t dst_off = 0; uint32_t dst_off = 0;
uint32_t last_out_len = 0;
uint8_t *key = sdcp->coh->aes_key; uint8_t *key = sdcp->coh->aes_key;
int ret = 0; int ret = 0;
int split = 0; int split = 0;
unsigned int i, len, clen, rem = 0; unsigned int i, len, clen, rem = 0, tlen = 0;
int init = 0; int init = 0;
bool limit_hit = false;
actx->fill = 0; 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) { for_each_sg(req->src, src, nents, i) {
src_buf = sg_virt(src); src_buf = sg_virt(src);
len = sg_dma_len(src); len = sg_dma_len(src);
tlen += len;
limit_hit = tlen > req->nbytes;
if (limit_hit)
len = req->nbytes - (tlen - len);
do { do {
if (actx->fill + len > out_off) 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, * If we filled the buffer or this is the last SG,
* submit the buffer. * 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); ret = mxs_dcp_run_aes(actx, req, init);
if (ret) if (ret)
return ret; return ret;
init = 0; init = 0;
out_tmp = out_buf; out_tmp = out_buf;
last_out_len = actx->fill;
while (dst && actx->fill) { while (dst && actx->fill) {
if (!split) { if (!split) {
dst_buf = sg_virt(dst); dst_buf = sg_virt(dst);
@ -350,6 +366,19 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
} }
} }
} while (len); } 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; return ret;