From: Zhushuai Yin <yinzhushuai@huawei.com> In the provider async paths, the async_pause_job failure branch used a single goto that either returned failure or jumped to cleanup, conflating the two cases and causing poll task slot leaks when pause_job returned zero. BN_bn2binpad() in the ECC private key conversion could return negative, which was stored directly into prikey.dsize and passed to the hardware, causing invalid key setup. The digest final path did not handle SWITCH_SOFT, treating a soft-switch return as a hard failure and breaking digest fallback. Split the async_pause_job error branch in the cipher, digest, DH and pkey provider paths to goto free_poll_task on ret==0 and return failure on req->state, preventing poll task slot leaks. Check BN_bn2binpad() return for negative in ECC private key setup and return UADK_P_FAIL. Handle UADK_DIGEST_SWITCH_SOFT in the digest final path by falling through to the sync error path instead of returning failure. Signed-off-by: Zhushuai Yin <yinzhushuai@huawei.com> --- src/uadk_prov_cipher.c | 6 ++++-- src/uadk_prov_dh.c | 2 +- src/uadk_prov_digest.c | 12 ++++++++---- src/uadk_prov_pkey.c | 10 ++++++++-- src/uadk_prov_rsa_sign.c | 2 +- 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/uadk_prov_cipher.c b/src/uadk_prov_cipher.c index c9ae006..caff75b 100644 --- a/src/uadk_prov_cipher.c +++ b/src/uadk_prov_cipher.c @@ -563,7 +563,7 @@ static int uadk_do_cipher_sync(struct cipher_priv_ctx *priv) int ret; ret = wd_do_cipher_sync(priv->sess, &priv->req); - if (ret) + if (ret || priv->req.state) return UADK_P_FAIL; return UADK_P_SUCCESS; @@ -602,7 +602,9 @@ static int uadk_do_cipher_async(struct cipher_priv_ctx *priv, struct async_op *o } while (true); ret = async_pause_job(priv, op, ASYNC_TASK_CIPHER); - if (!ret || priv->req.state) + if (!ret) + goto free_poll_task; + if (priv->req.state) return UADK_P_FAIL; return UADK_P_SUCCESS; diff --git a/src/uadk_prov_dh.c b/src/uadk_prov_dh.c index 004b60e..870f299 100644 --- a/src/uadk_prov_dh.c +++ b/src/uadk_prov_dh.c @@ -941,7 +941,7 @@ static int uadk_prov_dh_do_crypto(struct uadk_dh_sess *dh_sess) ret = async_pause_job(dh_sess, &op, ASYNC_TASK_DH); if (!ret) - goto err; + goto free_poll_task; ret = dh_sess->req.status; if (ret) diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index 7488fc6..3334662 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -623,7 +623,7 @@ static int uadk_do_digest_sync(struct digest_priv_ctx *priv) return UADK_DIGEST_FAIL; ret = wd_do_digest_sync(priv->sess, &priv->req); - if (ret) { + if (ret || priv->req.state) { UADK_ERR("do sec digest sync failed, switch to soft digest.\n"); return UADK_DIGEST_FAIL; } @@ -666,7 +666,9 @@ static int uadk_do_digest_async(struct digest_priv_ctx *priv, struct async_op *o } while (true); ret = async_pause_job(priv, op, ASYNC_TASK_DIGEST); - if (!ret || priv->req.state) + if (!ret) + goto free_poll_task; + if (priv->req.state) return UADK_DIGEST_FAIL; return UADK_DIGEST_SUCCESS; @@ -693,7 +695,9 @@ static int uadk_digest_final(struct digest_priv_ctx *priv, unsigned char *digest } ret = uadk_digest_ctx_init(priv); - if (ret != UADK_DIGEST_SUCCESS) + if (ret == UADK_DIGEST_SWITCH_SOFT) + goto sync_err; + else if (ret != UADK_DIGEST_SUCCESS) return UADK_DIGEST_FAIL; priv->req.in = priv->data; @@ -722,7 +726,7 @@ static int uadk_digest_final(struct digest_priv_ctx *priv, unsigned char *digest sync_err: if (priv->state == SEC_DIGEST_INIT) { - ret = uadk_digest_soft_work(priv, priv->req.in_bytes, digest); + ret = uadk_digest_soft_work(priv, priv->last_update_bufflen, digest); } else { ret = UADK_DIGEST_FAIL; UADK_ERR("do sec digest final failed.\n"); diff --git a/src/uadk_prov_pkey.c b/src/uadk_prov_pkey.c index 68750bd..0d392ca 100644 --- a/src/uadk_prov_pkey.c +++ b/src/uadk_prov_pkey.c @@ -427,7 +427,7 @@ int uadk_prov_ecc_crypto(handle_t sess, struct wd_ecc_req *req, void *usr) ret = async_pause_job(usr, &op, ASYNC_TASK_ECC); if (ret == 0) - goto err; + goto free_poll_task; if (req->status) goto err; @@ -715,6 +715,7 @@ int uadk_prov_ecc_set_private_key(handle_t sess, const EC_KEY *ec) struct wd_dtb prikey; const BIGNUM *d; int buflen, ret; + int tmplen; size_t degree; d = EC_KEY_get0_private_key(ec); @@ -733,7 +734,12 @@ int uadk_prov_ecc_set_private_key(handle_t sess, const EC_KEY *ec) buflen = BITS_TO_BYTES(degree); ecc_key = wd_ecc_get_key(sess); prikey.data = (void *)prikey_bin; - prikey.dsize = BN_bn2binpad(d, prikey_bin, buflen); + tmplen = BN_bn2binpad(d, prikey_bin, buflen); + if (tmplen < 0) { + UADK_ERR("failed to convert ecc private key\n"); + return UADK_P_FAIL; + } + prikey.dsize = tmplen; ret = wd_ecc_set_prikey(ecc_key, &prikey); if (ret) { diff --git a/src/uadk_prov_rsa_sign.c b/src/uadk_prov_rsa_sign.c index e9f9651..370dcc1 100644 --- a/src/uadk_prov_rsa_sign.c +++ b/src/uadk_prov_rsa_sign.c @@ -349,7 +349,7 @@ static int verify_trans_bn(struct uadk_rsa_sess *rsa_sess, unsigned char *from_b goto verify_end; *len = BN_bn2binpad(verify_bn, from_buf, num_bytes); - if (*len == 0) + if (*len <= 0) ret = UADK_P_FAIL; verify_end: -- 2.43.0