[PATCH v2] crypto: chelsio - Fix wrcount leak in AES encrypt and decrypt
From: Wentao Liang
Date: Fri Nov 06 2026 - 02:38:27 EST
chcr_aes_encrypt() and chcr_aes_decrypt() increment the device inflight
count with chcr_inc_wrcount() before building the work request, but both
can return early without dropping the count.
chcr_aes_encrypt() leaks the count when process_cipher() fails or
returns no skb. chcr_aes_decrypt() leaks it when the tx queue is full or
when process_cipher() fails and returns no skb. No completion can
balance those increments, so every failed request permanently skews the
count and eventually blocks the device from being detached, with the
detach worker warning "CHCR:request Still Pending".
chcr_aes_encrypt() already has an error label that calls
chcr_dec_wrcount(), so jump to it on the remaining failure path. Add the
same label to chcr_aes_decrypt() and jump to it from both of its failure
paths, mirroring the encrypt side.
Fixes: fef4912b66d6 ("crypto: chelsio - Handle PCI shutdown event")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Wentao Liang <vulab@xxxxxxxxxxx>
---
Changes in v2:
- Fix chcr_aes_encrypt() and chcr_aes_decrypt() in a single patch, as
requested. Sorry for the late reply.
- Link to v1: https://lore.kernel.org/all/20260916092527.2002187-1-vulab@xxxxxxxxxxx/
https://lore.kernel.org/all/20260916092359.2001753-1-vulab@xxxxxxxxxxx/
---
drivers/crypto/chelsio/chcr_algo.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c
index e2f2b2a6200e..9ce9eefef777 100644
--- a/drivers/crypto/chelsio/chcr_algo.c
+++ b/drivers/crypto/chelsio/chcr_algo.c
@@ -1359,7 +1359,7 @@ static int chcr_aes_encrypt(struct skcipher_request *req)
err = process_cipher(req, u_ctx->lldi.rxq_ids[reqctx->rxqidx],
&skb, CHCR_ENCRYPT_OP);
if (err || !skb)
- return err;
+ goto error;
skb->dev = u_ctx->lldi.ports[0];
set_wr_txq(skb, CPL_PRIORITY_DATA, reqctx->txqidx);
chcr_send_wr(skb);
@@ -1397,16 +1397,21 @@ static int chcr_aes_decrypt(struct skcipher_request *req)
if (unlikely(cxgb4_is_crypto_q_full(u_ctx->lldi.ports[0],
reqctx->txqidx) &&
- (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))))
- return -ENOSPC;
+ (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)))) {
+ err = -ENOSPC;
+ goto error;
+ }
err = process_cipher(req, u_ctx->lldi.rxq_ids[reqctx->rxqidx],
&skb, CHCR_DECRYPT_OP);
if (err || !skb)
- return err;
+ goto error;
skb->dev = u_ctx->lldi.ports[0];
set_wr_txq(skb, CPL_PRIORITY_DATA, reqctx->txqidx);
chcr_send_wr(skb);
return -EINPROGRESS;
+error:
+ chcr_dec_wrcount(dev);
+ return err;
}
static int chcr_device_init(struct chcr_context *ctx)
{
--
2.34.1