When do sm2 async task with the digest method, there is a probability of segment fault occurring: | SM2_sign_loop | EVP_DigestSign | [...] | sm2_sign | sm2_sign_init_iot | wd_sm2_new_sign_in | [...] | uadk_ecc_get_rand | [...] | RAND_bytes | [...] | rand_bytes | EVP_DigestFinal_ex | uadk_e_digest_cleanup | wd_digest_free_sess | wd_memset_zero The wd_memset_zero() will release the sess and the addr of async job may get changed and will cause segment fault.
The solution is to make async callback param use the memory on heap rather than stack, or other cleanup related functions may release the memory on stack and modify the address of cb param in unknown scense.
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com --- src/uadk_digest.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-)
diff --git a/src/uadk_digest.c b/src/uadk_digest.c index b75c408..d9b36e1 100644 --- a/src/uadk_digest.c +++ b/src/uadk_digest.c @@ -715,22 +715,29 @@ static int do_digest_sync(struct digest_priv_ctx *priv)
static int do_digest_async(struct digest_priv_ctx *priv, struct async_op *op) { - struct uadk_e_cb_info cb_param; - int idx, ret; + struct uadk_e_cb_info *cb_param; + int ret = 0; + int idx;
if (unlikely(priv->switch_flag == UADK_DO_SOFT)) { fprintf(stderr, "async cipher init failed.\n"); - return 0; + return ret; + } + + cb_param = malloc(sizeof(struct uadk_e_cb_info)); + if (!cb_param) { + fprintf(stderr, "failed to alloc cb_param.\n"); + return ret; }
- cb_param.op = op; - cb_param.priv = priv; + cb_param->op = op; + cb_param->priv = priv; priv->req.cb = uadk_e_digest_cb; - priv->req.cb_param = &cb_param; + priv->req.cb_param = cb_param;
ret = async_get_free_task(&idx); if (!ret) - return 0; + goto free_cb_param;
op->idx = idx;
@@ -739,14 +746,16 @@ static int do_digest_async(struct digest_priv_ctx *priv, struct async_op *op) if (ret < 0 && ret != -EBUSY) { fprintf(stderr, "do sec digest async failed.\n"); async_free_poll_task(op->idx, 0); - return 0; + ret = 0; + goto free_cb_param; } } while (ret == -EBUSY);
ret = async_pause_job(priv, op, ASYNC_TASK_DIGEST, idx); - if (!ret) - return 0; - return 1; + +free_cb_param: + free(cb_param); + return ret; }
static int uadk_e_digest_final(EVP_MD_CTX *ctx, unsigned char *digest) @@ -773,7 +782,7 @@ static int uadk_e_digest_final(EVP_MD_CTX *ctx, unsigned char *digest) return 0; }
- if (op.job == NULL) { + if (!op.job) { /* Synchronous, only the synchronous mode supports soft computing */ if (unlikely(priv->switch_flag == UADK_DO_SOFT)) { ret = digest_soft_final(priv, digest); @@ -801,7 +810,7 @@ sync_err: fprintf(stderr, "do sec digest stream mode failed.\n"); } clear: - async_clear_async_event_notification(); + (void)async_clear_async_event_notification(); return ret; }