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

Commit 1e475dc4 authored by Tudor Ambarus's avatar Tudor Ambarus Committed by Greg Kroah-Hartman
Browse files

crypto: atmel-aes - Fix IV handling when req->nbytes < ivsize



commit 86ef1dfcb561473fbf5e199d58d18c55554d78be upstream.

commit 394a9e044702 ("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: 91308019 ("crypto: atmel-aes - properly set IV after {en,de}crypt")
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarTudor Ambarus <tudor.ambarus@microchip.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0d51b4d8
Loading
Loading
Loading
Loading
+30 −23
Original line number Diff line number Diff line
@@ -493,37 +493,42 @@ 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 inline int atmel_aes_complete(struct atmel_aes_dev *dd, int err)
static void atmel_aes_set_iv_as_last_ciphertext_block(struct atmel_aes_dev *dd)
{
#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
	if (dd->ctx->is_aead)
		atmel_aes_authenc_complete(dd, err);
#endif

	clk_disable(dd->iclk);
	dd->flags &= ~AES_FLAGS_BUSY;

	if (!dd->ctx->is_aead) {
		struct ablkcipher_request *req =
			ablkcipher_request_cast(dd->areq);
	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);
	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) {
		if (req->src == req->dst)
			memcpy(req->info, rctx->lastc, ivsize);
			} else {
		else
			scatterwalk_map_and_copy(req->info, req->src,
					req->nbytes - ivsize, ivsize, 0);
			}
						 req->nbytes - ivsize,
						 ivsize, 0);
	}
}

static inline int atmel_aes_complete(struct atmel_aes_dev *dd, int err)
{
#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
	if (dd->ctx->is_aead)
		atmel_aes_authenc_complete(dd, err);
#endif

	clk_disable(dd->iclk);
	dd->flags &= ~AES_FLAGS_BUSY;

	if (!dd->ctx->is_aead)
		atmel_aes_set_iv_as_last_ciphertext_block(dd);

	if (dd->is_async)
		dd->areq->complete(dd->areq, err);

@@ -1128,10 +1133,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);

		if (req->nbytes >= ivsize)
			scatterwalk_map_and_copy(rctx->lastc, req->src,
			(req->nbytes - ivsize), ivsize, 0);
						 req->nbytes - ivsize,
						 ivsize, 0);
	}

	return atmel_aes_handle_queue(dd, &req->base);