diff mbox series

crypto: caam - limit output IV to CBC to work around CTR mode DMA issue

Message ID 20190531081306.30359-1-ard.biesheuvel@linaro.org (mailing list archive)
State Accepted
Delegated to: Herbert Xu
Headers show
Series crypto: caam - limit output IV to CBC to work around CTR mode DMA issue | expand

Commit Message

Ard Biesheuvel May 31, 2019, 8:13 a.m. UTC
The CAAM driver currently violates an undocumented and slightly
controversial requirement imposed by the crypto stack that a buffer
referred to by the request structure via its virtual address may not
be modified while any scatterlists passed via the same request
structure are mapped for inbound DMA.

This may result in errors like

  alg: aead: decryption failed on test 1 for gcm_base(ctr-aes-caam,ghash-generic): ret=74
  alg: aead: Failed to load transform for gcm(aes): -2

on non-cache coherent systems, due to the fact that the GCM driver
passes an IV buffer by virtual address which shares a cacheline with
the auth_tag buffer passed via a scatterlist, resulting in corruption
of the auth_tag when the IV is updated while the DMA mapping is live.

Since the IV that is returned to the caller is only valid for CBC mode,
and given that the in-kernel users of CBC (such as CTS) don't trigger the
same issue as the GCM driver, let's just disable the output IV generation
for all modes except CBC for the time being.

Cc: Horia Geanta <horia.geanta@nxp.com>
Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
Reported-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 drivers/crypto/caam/caamalg.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

Comments

Horia Geanta May 31, 2019, 2:21 p.m. UTC | #1
On 5/31/2019 11:14 AM, Ard Biesheuvel wrote:
> The CAAM driver currently violates an undocumented and slightly
> controversial requirement imposed by the crypto stack that a buffer
> referred to by the request structure via its virtual address may not
> be modified while any scatterlists passed via the same request
> structure are mapped for inbound DMA.
> 
IMO this requirement developed while discussing current issue,
it did not exist a priori.

> This may result in errors like
> 
>   alg: aead: decryption failed on test 1 for gcm_base(ctr-aes-caam,ghash-generic): ret=74
>   alg: aead: Failed to load transform for gcm(aes): -2
> 
> on non-cache coherent systems, due to the fact that the GCM driver
> passes an IV buffer by virtual address which shares a cacheline with
> the auth_tag buffer passed via a scatterlist, resulting in corruption
> of the auth_tag when the IV is updated while the DMA mapping is live.
> 
> Since the IV that is returned to the caller is only valid for CBC mode,
> and given that the in-kernel users of CBC (such as CTS) don't trigger the
> same issue as the GCM driver, let's just disable the output IV generation
> for all modes except CBC for the time being.
> 
> Cc: Horia Geanta <horia.geanta@nxp.com>
> Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
> Reported-by: Sascha Hauer <s.hauer@pengutronix.de>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Link: https://lore.kernel.org/linux-crypto/1559149856-7938-1-git-send-email-iuliana.prodan@nxp.com/
Reviewed-by: Horia Geanta <horia.geanta@nxp.com>

Unfortunately this does not apply cleanly to -stable, I'll send a backport
once it hits mainline.

Thanks,
Horia
Ard Biesheuvel May 31, 2019, 2:29 p.m. UTC | #2
On Fri, 31 May 2019 at 16:21, Horia Geanta <horia.geanta@nxp.com> wrote:
>
> On 5/31/2019 11:14 AM, Ard Biesheuvel wrote:
> > The CAAM driver currently violates an undocumented and slightly
> > controversial requirement imposed by the crypto stack that a buffer
> > referred to by the request structure via its virtual address may not
> > be modified while any scatterlists passed via the same request
> > structure are mapped for inbound DMA.
> >
> IMO this requirement developed while discussing current issue,
> it did not exist a priori.
>

I won't argue with that.

> > This may result in errors like
> >
> >   alg: aead: decryption failed on test 1 for gcm_base(ctr-aes-caam,ghash-generic): ret=74
> >   alg: aead: Failed to load transform for gcm(aes): -2
> >
> > on non-cache coherent systems, due to the fact that the GCM driver
> > passes an IV buffer by virtual address which shares a cacheline with
> > the auth_tag buffer passed via a scatterlist, resulting in corruption
> > of the auth_tag when the IV is updated while the DMA mapping is live.
> >
> > Since the IV that is returned to the caller is only valid for CBC mode,
> > and given that the in-kernel users of CBC (such as CTS) don't trigger the
> > same issue as the GCM driver, let's just disable the output IV generation
> > for all modes except CBC for the time being.
> >
> > Cc: Horia Geanta <horia.geanta@nxp.com>
> > Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
> > Reported-by: Sascha Hauer <s.hauer@pengutronix.de>
> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Link: https://lore.kernel.org/linux-crypto/1559149856-7938-1-git-send-email-iuliana.prodan@nxp.com/
> Reviewed-by: Horia Geanta <horia.geanta@nxp.com>
>
> Unfortunately this does not apply cleanly to -stable, I'll send a backport
> once it hits mainline.
>

Thanks.
Herbert Xu May 31, 2019, 2:48 p.m. UTC | #3
On Fri, May 31, 2019 at 02:21:40PM +0000, Horia Geanta wrote:
>
> IMO this requirement developed while discussing current issue,
> it did not exist a priori.

Well this requirement has always existed because there has never
been an API requirement that says you must place the IV on a
different cache-line from the src/dst scatter list.

So this isn't really a new requirement, we simply discovered a bug
in the caam code.

Cheers,
Herbert Xu June 6, 2019, 6:54 a.m. UTC | #4
On Fri, May 31, 2019 at 10:13:06AM +0200, Ard Biesheuvel wrote:
> The CAAM driver currently violates an undocumented and slightly
> controversial requirement imposed by the crypto stack that a buffer
> referred to by the request structure via its virtual address may not
> be modified while any scatterlists passed via the same request
> structure are mapped for inbound DMA.
> 
> This may result in errors like
> 
>   alg: aead: decryption failed on test 1 for gcm_base(ctr-aes-caam,ghash-generic): ret=74
>   alg: aead: Failed to load transform for gcm(aes): -2
> 
> on non-cache coherent systems, due to the fact that the GCM driver
> passes an IV buffer by virtual address which shares a cacheline with
> the auth_tag buffer passed via a scatterlist, resulting in corruption
> of the auth_tag when the IV is updated while the DMA mapping is live.
> 
> Since the IV that is returned to the caller is only valid for CBC mode,
> and given that the in-kernel users of CBC (such as CTS) don't trigger the
> same issue as the GCM driver, let's just disable the output IV generation
> for all modes except CBC for the time being.
> 
> Cc: Horia Geanta <horia.geanta@nxp.com>
> Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
> Reported-by: Sascha Hauer <s.hauer@pengutronix.de>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  drivers/crypto/caam/caamalg.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)

Patch applied.  Thanks.
diff mbox series

Patch

diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index c0ece44f303b..e1778e209ea2 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -999,6 +999,7 @@  static void skcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
 	struct skcipher_request *req = context;
 	struct skcipher_edesc *edesc;
 	struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+	struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
 	int ivsize = crypto_skcipher_ivsize(skcipher);
 
 #ifdef DEBUG
@@ -1023,9 +1024,9 @@  static void skcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
 
 	/*
 	 * The crypto API expects us to set the IV (req->iv) to the last
-	 * ciphertext block. This is used e.g. by the CTS mode.
+	 * ciphertext block when running in CBC mode.
 	 */
-	if (ivsize)
+	if ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CBC)
 		scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen -
 					 ivsize, ivsize, 0);
 
@@ -1842,9 +1843,9 @@  static int skcipher_decrypt(struct skcipher_request *req)
 
 	/*
 	 * The crypto API expects us to set the IV (req->iv) to the last
-	 * ciphertext block.
+	 * ciphertext block when running in CBC mode.
 	 */
-	if (ivsize)
+	if ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CBC)
 		scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen -
 					 ivsize, ivsize, 0);