[PATCH v2 2/5] crypto: hisilicon/sec2 - fix UAF in sec_alg_send_backlog

From: ZongYu Wu

Date: Thu May 28 2026 - 07:58:10 EST


From: Wenkai Lin <linwenkai6@xxxxxxxxxxxxx>

After crypto_request_complete() is invoked, the crypto core may
immediately free the request structure and its associated tfm context.
Consequently, the sec_ctx and qp_ctx are also released.

However, sec_alg_send_backlog() can still attempt to access these
structures when processing queued requests, resulting in a
use-after-free (UAF) bug.

Fix this by accessing the backlog list through the long-term qp memory
and using the ctx memory only when the backlog list is not empty.

Fixes: f0ae287c5045 ("crypto: hisilicon/sec2 - implement full backlog mode for sec")
Signed-off-by: Wenkai Lin <linwenkai6@xxxxxxxxxxxxx>
Signed-off-by: Zongyu Wu <wuzongyu1@xxxxxxxxxx>
---
drivers/crypto/hisilicon/sec2/sec_crypto.c | 23 +++++++++++-----------
1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c
index 77e0e03cbcab..62125cf1f849 100644
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c
@@ -234,13 +234,15 @@ static int qp_send_message(struct sec_req *req)
return -EINPROGRESS;
}

-static void sec_alg_send_backlog_soft(struct sec_ctx *ctx, struct sec_qp_ctx *qp_ctx)
+static void sec_alg_send_backlog_soft(struct hisi_qp *qp)
{
struct sec_req *req, *tmp;
+ struct sec_ctx *ctx;
int ret;

- list_for_each_entry_safe(req, tmp, &qp_ctx->qp->backlog.list, list) {
+ list_for_each_entry_safe(req, tmp, &qp->backlog.list, list) {
list_del(&req->list);
+ ctx = req->qp_ctx->ctx;
ctx->req_op->buf_unmap(ctx, req);
if (req->req_id >= 0)
sec_free_req_id(req);
@@ -258,9 +260,8 @@ static void sec_alg_send_backlog_soft(struct sec_ctx *ctx, struct sec_qp_ctx *qp
}
}

-static void sec_alg_send_backlog(struct sec_ctx *ctx, struct sec_qp_ctx *qp_ctx)
+static void sec_alg_send_backlog(struct hisi_qp *qp)
{
- struct hisi_qp *qp = qp_ctx->qp;
struct sec_req *req, *tmp;
int ret;

@@ -277,7 +278,7 @@ static void sec_alg_send_backlog(struct sec_ctx *ctx, struct sec_qp_ctx *qp_ctx)
goto unlock;
default:
/* Release memory resources and send all requests through software. */
- sec_alg_send_backlog_soft(ctx, qp_ctx);
+ sec_alg_send_backlog_soft(qp);
goto unlock;
}
}
@@ -306,6 +307,7 @@ static void sec_req_cb(struct hisi_qp *qp, void *resp)

ctx->req_op->buf_unmap(ctx, req);
ctx->req_op->callback(ctx, req, err);
+ sec_alg_send_backlog(qp);
}

static void sec_req_cb3(struct hisi_qp *qp, void *resp)
@@ -331,6 +333,7 @@ static void sec_req_cb3(struct hisi_qp *qp, void *resp)

ctx->req_op->buf_unmap(ctx, req);
ctx->req_op->callback(ctx, req, err);
+ sec_alg_send_backlog(qp);
}

static int sec_alg_send_message_retry(struct sec_req *req)
@@ -1673,8 +1676,6 @@ static void sec_update_iv(struct sec_req *req, enum sec_alg_type alg_type)
static void sec_skcipher_callback(struct sec_ctx *ctx, struct sec_req *req,
int err)
{
- struct sec_qp_ctx *qp_ctx = req->qp_ctx;
-
if (req->req_id >= 0)
sec_free_req_id(req);

@@ -1684,7 +1685,6 @@ static void sec_skcipher_callback(struct sec_ctx *ctx, struct sec_req *req,
sec_update_iv(req, SEC_SKCIPHER);

crypto_request_complete(req->base, err);
- sec_alg_send_backlog(ctx, qp_ctx);
}

static void set_aead_auth_iv(struct sec_ctx *ctx, struct sec_req *req)
@@ -1923,7 +1923,7 @@ static void sec_aead_callback(struct sec_ctx *c, struct sec_req *req, int err)
struct aead_request *a_req = req->aead_req.aead_req;
struct crypto_aead *tfm = crypto_aead_reqtfm(a_req);
size_t authsize = crypto_aead_authsize(tfm);
- struct sec_qp_ctx *qp_ctx = req->qp_ctx;
+ int error = err;
size_t sz;

if (!err && req->c_req.encrypt) {
@@ -1934,15 +1934,14 @@ static void sec_aead_callback(struct sec_ctx *c, struct sec_req *req, int err)
authsize, a_req->cryptlen + a_req->assoclen);
if (unlikely(sz != authsize)) {
dev_err(c->dev, "copy out mac err!\n");
- err = -EINVAL;
+ error = -EINVAL;
}
}

if (req->req_id >= 0)
sec_free_req_id(req);

- crypto_request_complete(req->base, err);
- sec_alg_send_backlog(c, qp_ctx);
+ crypto_request_complete(req->base, error);
}

static void sec_request_uninit(struct sec_req *req)
--
2.33.0