qce_aead_crypt() records a per-request decision to use the software fallback (on zero-length message) in ctx->need_fallback, which lives in the TFM context shared by all concurrent requests on the transform, and then clears it again. This has two problems: 1. Concurrent requests race on the flag: one request can observe and clear the flag set for another, so that a request that needs the fallback is sent to the engine while an unrelated one is diverted to the fallback. 2. ctx->need_fallback is also set by setkey() for AES-192 keys, which the engine cannot handle for any request. Clearing it after the first fallback request makes every following request on that TFM go to the hardware with an unsupported key size. Use a local variable seeded from the per-TFM flag for the per-request decision and stop clearing the flag. Fixes: b51dcf05c1e9 ("crypto: qce - Schedule fallback aead algorithm") Cc: stable@vger.kernel.org Signed-off-by: Bartosz Golaszewski --- drivers/crypto/qce/aead.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/crypto/qce/aead.c b/drivers/crypto/qce/aead.c index e0061bfab216861444e36700d6530e7a3cd347e7..b7873852249dffeb91d09df3bae6534f77c08b7e 100644 --- a/drivers/crypto/qce/aead.c +++ b/drivers/crypto/qce/aead.c @@ -499,6 +499,7 @@ static int qce_aead_crypt(struct aead_request *req, int encrypt) struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm); struct qce_alg_template *tmpl = to_aead_tmpl(tfm); unsigned int blocksize = crypto_aead_blocksize(tfm); + bool fallback = ctx->need_fallback; rctx->flags = tmpl->alg_flags; rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT; @@ -511,14 +512,11 @@ static int qce_aead_crypt(struct aead_request *req, int encrypt) /* CE does not handle 0 length messages */ if (!rctx->cryptlen) { if (!(IS_CCM(rctx->flags) && IS_DECRYPT(rctx->flags))) - ctx->need_fallback = true; + fallback = true; } /* If fallback is needed, schedule and exit */ - if (ctx->need_fallback) { - /* Reset need_fallback in case the same ctx is used for another transaction */ - ctx->need_fallback = false; - + if (fallback) { aead_request_set_tfm(&rctx->fallback_req, ctx->fallback); aead_request_set_callback(&rctx->fallback_req, req->base.flags, req->base.complete, req->base.data); @@ -577,8 +575,7 @@ static int qce_aead_ccm_setkey(struct crypto_aead *tfm, const u8 *key, memcpy(ctx->enc_key, key, keylen); memcpy(ctx->auth_key, key, keylen); - if (keylen == AES_KEYSIZE_192) - ctx->need_fallback = true; + ctx->need_fallback = (keylen == AES_KEYSIZE_192); return IS_CCM_RFC4309(flags) ? crypto_aead_setkey(ctx->fallback, key, keylen + QCE_CCM4309_SALT_SIZE) : @@ -606,8 +603,7 @@ static int qce_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int authenc_keys.enckeylen != AES_KEYSIZE_192 && authenc_keys.enckeylen != AES_KEYSIZE_256) return -EINVAL; - if (authenc_keys.enckeylen == AES_KEYSIZE_192) - ctx->need_fallback = true; + ctx->need_fallback = (authenc_keys.enckeylen == AES_KEYSIZE_192); } ctx->enc_keylen = authenc_keys.enckeylen; -- 2.47.3