crypto: atmel-aes - Fix IV handling when req->nbytes < ivsize
commit394a9e0447
("crypto: cfb - add missing 'chunksize' property") adds a test vector where the input length is smaller than the IV length (the second test vector). This revealed a NULL pointer dereference in the atmel-aes driver, that is caused by passing an incorrect offset in scatterwalk_map_and_copy() when atmel_aes_complete() is called. Do not save the IV in req->info of ablkcipher_request (or equivalently req->iv of skcipher_request) when req->nbytes < ivsize, because the IV will not be further used. While touching the code, modify the type of ivsize from int to unsigned int, to comply with the return type of crypto_ablkcipher_ivsize(). Fixes:91308019ec
("crypto: atmel-aes - properly set IV after {en,de}crypt") Cc: <stable@vger.kernel.org> Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
parent
830536770f
commit
86ef1dfcb5
|
@ -490,6 +490,29 @@ static inline bool atmel_aes_is_encrypt(const struct atmel_aes_dev *dd)
|
|||
static void atmel_aes_authenc_complete(struct atmel_aes_dev *dd, int err);
|
||||
#endif
|
||||
|
||||
static void atmel_aes_set_iv_as_last_ciphertext_block(struct atmel_aes_dev *dd)
|
||||
{
|
||||
struct ablkcipher_request *req = ablkcipher_request_cast(dd->areq);
|
||||
struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req);
|
||||
struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
|
||||
unsigned int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
|
||||
|
||||
if (req->nbytes < ivsize)
|
||||
return;
|
||||
|
||||
if (rctx->mode & AES_FLAGS_ENCRYPT) {
|
||||
scatterwalk_map_and_copy(req->info, req->dst,
|
||||
req->nbytes - ivsize, ivsize, 0);
|
||||
} else {
|
||||
if (req->src == req->dst)
|
||||
memcpy(req->info, rctx->lastc, ivsize);
|
||||
else
|
||||
scatterwalk_map_and_copy(req->info, req->src,
|
||||
req->nbytes - ivsize,
|
||||
ivsize, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int atmel_aes_complete(struct atmel_aes_dev *dd, int err)
|
||||
{
|
||||
#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
|
||||
|
@ -500,26 +523,8 @@ static inline int atmel_aes_complete(struct atmel_aes_dev *dd, int err)
|
|||
clk_disable(dd->iclk);
|
||||
dd->flags &= ~AES_FLAGS_BUSY;
|
||||
|
||||
if (!dd->ctx->is_aead) {
|
||||
struct ablkcipher_request *req =
|
||||
ablkcipher_request_cast(dd->areq);
|
||||
struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req);
|
||||
struct crypto_ablkcipher *ablkcipher =
|
||||
crypto_ablkcipher_reqtfm(req);
|
||||
int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
|
||||
|
||||
if (rctx->mode & AES_FLAGS_ENCRYPT) {
|
||||
scatterwalk_map_and_copy(req->info, req->dst,
|
||||
req->nbytes - ivsize, ivsize, 0);
|
||||
} else {
|
||||
if (req->src == req->dst) {
|
||||
memcpy(req->info, rctx->lastc, ivsize);
|
||||
} else {
|
||||
scatterwalk_map_and_copy(req->info, req->src,
|
||||
req->nbytes - ivsize, ivsize, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dd->ctx->is_aead)
|
||||
atmel_aes_set_iv_as_last_ciphertext_block(dd);
|
||||
|
||||
if (dd->is_async)
|
||||
dd->areq->complete(dd->areq, err);
|
||||
|
@ -1125,10 +1130,12 @@ static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
|
|||
rctx->mode = mode;
|
||||
|
||||
if (!(mode & AES_FLAGS_ENCRYPT) && (req->src == req->dst)) {
|
||||
int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
|
||||
unsigned int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
|
||||
|
||||
scatterwalk_map_and_copy(rctx->lastc, req->src,
|
||||
(req->nbytes - ivsize), ivsize, 0);
|
||||
if (req->nbytes >= ivsize)
|
||||
scatterwalk_map_and_copy(rctx->lastc, req->src,
|
||||
req->nbytes - ivsize,
|
||||
ivsize, 0);
|
||||
}
|
||||
|
||||
return atmel_aes_handle_queue(dd, &req->base);
|
||||
|
|
Loading…
Reference in New Issue