Linux cryptographic layer development
 help / color / mirror / Atom feed
From: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
To: Herbert Xu <herbert@gondor.apana.org.au>,
	Linux Crypto Mailing List <linux-crypto@vger.kernel.org>,
	Ard Biesheuvel <ardb@kernel.org>
Subject: Re: [PATCH] crypto: arm64/aes-ccm - Rewrite skcipher walker loop
Date: Wed, 1 Feb 2023 10:53:37 +0800	[thread overview]
Message-ID: <b83ca139-1e8c-60f3-939f-15f727710c36@linux.alibaba.com> (raw)
In-Reply-To: <Y9eGyzZ+JAqRQvtm@gondor.apana.org.au>



On 1/30/23 4:58 PM, Herbert Xu wrote:
> An often overlooked aspect of the skcipher walker API is that an
> error is not just indicated by a non-zero return value, but by the
> fact that walk->nbytes is zero.
> 
> Thus it is an error to call skcipher_walk_done after getting back
> walk->nbytes == 0 from the previous interaction with the walker.
> 
> This is because when walk->nbytes is zero the walker is left in
> an undefined state and any further calls to it may try to free
> uninitialised stack memory.
> 
> The arm64 ccm code has to deal with zero-length messages, and
> it needs to process data even when walk->nbytes == 0 is returned.
> It doesn't have this bug because there is an explicit check for
> walk->nbytes != 0 prior to the skcipher_walk_done call.
> 
> However, the loop is still sufficiently different from the usual
> layout and it appears to have been copied into other code which
> then ended up with this bug.  This patch rewrites it to follow the
> usual convention of checking walk->nbytes.
> 
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
> 
> diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c
> index c4f14415f5f0..25cd3808ecbe 100644
> --- a/arch/arm64/crypto/aes-ce-ccm-glue.c
> +++ b/arch/arm64/crypto/aes-ce-ccm-glue.c
> @@ -161,43 +161,39 @@ static int ccm_encrypt(struct aead_request *req)
>   	memcpy(buf, req->iv, AES_BLOCK_SIZE);
>   
>   	err = skcipher_walk_aead_encrypt(&walk, req, false);
> -	if (unlikely(err))
> -		return err;
>   
>   	kernel_neon_begin();
>   
>   	if (req->assoclen)
>   		ccm_calculate_auth_mac(req, mac);
>   
> -	do {
> +	while (walk.nbytes) {
>   		u32 tail = walk.nbytes % AES_BLOCK_SIZE;
> +		bool final = walk.nbytes == walk.total;
>   
> -		if (walk.nbytes == walk.total)
> +		if (final)
>   			tail = 0;
>   
>   		ce_aes_ccm_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
>   				   walk.nbytes - tail, ctx->key_enc,
>   				   num_rounds(ctx), mac, walk.iv);
>   
> -		if (walk.nbytes == walk.total)
> -			ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx));
> +		if (!final)
> +			kernel_neon_end();
> +		err = skcipher_walk_done(&walk, tail);
> +		if (!final)
> +			kernel_neon_begin();
> +	}
>   
> -		kernel_neon_end();
> +	ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx));
>   
> -		if (walk.nbytes) {
> -			err = skcipher_walk_done(&walk, tail);
> -			if (unlikely(err))
> -				return err;
> -			if (unlikely(walk.nbytes))
> -				kernel_neon_begin();
> -		}
> -	} while (walk.nbytes);
> +	kernel_neon_end();
>   
>   	/* copy authtag to end of dst */
>   	scatterwalk_map_and_copy(mac, req->dst, req->assoclen + req->cryptlen,
>   				 crypto_aead_authsize(aead), 1);
>   
> -	return 0;
> +	return err;
>   }

I think the following is a more cleaner rewriting form of the loop,
which handles the last chunk separately, and both gcm and ccm can be
handled similarly.

	while (walk.nbytes != walk.total) {
		u32 tail = walk.nbytes % AES_BLOCK_SIZE;

		ce_aes_ccm_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
				   walk.nbytes - tail, ctx->key_enc,
				   num_rounds(ctx), mac, walk.iv);

		kernel_neon_end();

		err = skcipher_walk_done(&walk, tail);

		kernel_neon_begin();
	}

	if (walk.nbytes) {
		ce_aes_ccm_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
				   walk.nbytes, ctx->key_enc,
				   num_rounds(ctx), mac, walk.iv);

		err = skcipher_walk_done(&walk, 0);
	}

	ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx));

	kernel_neon_end();


I have tested it initially. What are your opinions?

>   
>   static int ccm_decrypt(struct aead_request *req)
> @@ -219,37 +215,36 @@ static int ccm_decrypt(struct aead_request *req)
>   	memcpy(buf, req->iv, AES_BLOCK_SIZE);
>   
>   	err = skcipher_walk_aead_decrypt(&walk, req, false);
> -	if (unlikely(err))
> -		return err;
>   
>   	kernel_neon_begin();
>   
>   	if (req->assoclen)
>   		ccm_calculate_auth_mac(req, mac);
>   
> -	do {
> +	while (walk.nbytes) {
>   		u32 tail = walk.nbytes % AES_BLOCK_SIZE;
> +		bool final = walk.nbytes == walk.total;
>   
> -		if (walk.nbytes == walk.total)
> +		if (final)
>   			tail = 0;
>   
>   		ce_aes_ccm_decrypt(walk.dst.virt.addr, walk.src.virt.addr,
>   				   walk.nbytes - tail, ctx->key_enc,
>   				   num_rounds(ctx), mac, walk.iv);
>   
> -		if (walk.nbytes == walk.total)
> -			ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx));
> +		if (!final)
> +			kernel_neon_end();
> +		err = skcipher_walk_done(&walk, tail);
> +		if (!final)
> +			kernel_neon_begin();
> +	}
>   
> -		kernel_neon_end();
> +	ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx));
>   
> -		if (walk.nbytes) {
> -			err = skcipher_walk_done(&walk, tail);
> -			if (unlikely(err))
> -				return err;
> -			if (unlikely(walk.nbytes))
> -				kernel_neon_begin();
> -		}
> -	} while (walk.nbytes);
> +	kernel_neon_end();
> +
> +	if (unlikely(err))
> +		return err;
>   
>   	/* compare calculated auth tag with the stored one */
>   	scatterwalk_map_and_copy(buf, req->src,

  parent reply	other threads:[~2023-02-01  2:53 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-30  8:58 [PATCH] crypto: arm64/aes-ccm - Rewrite skcipher walker loop Herbert Xu
2023-01-30 10:42 ` Ard Biesheuvel
2023-01-31  3:19   ` Herbert Xu
2023-02-01  2:53 ` Tianjia Zhang [this message]
2023-02-01  8:55   ` Herbert Xu
2023-02-01  9:15     ` Tianjia Zhang
2023-02-01  9:21       ` Herbert Xu
2023-02-01  9:43         ` Tianjia Zhang
2023-02-01  9:50           ` Herbert Xu
2023-02-01  9:54             ` Tianjia Zhang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b83ca139-1e8c-60f3-939f-15f727710c36@linux.alibaba.com \
    --to=tianjia.zhang@linux.alibaba.com \
    --cc=ardb@kernel.org \
    --cc=herbert@gondor.apana.org.au \
    --cc=linux-crypto@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox