From: Weili Qian <qianweili@huawei.com> Multiple memory safety bugs across the driver and algorithm layers cause heap overflow, out-of-bounds reads, use-after-free, resource leaks, and uninitialized spinlocks that can lead to crashes and data corruption. The following five issues are addressed: wd_parse_log_level in wd.c allocated st_size bytes but fscanf "%[^\n ]" appends a '\0', causing off-by-one heap overflow when a token is exactly st_size long. _find_next_bit in wd_mempool.c used "start > bits" in the loop guard while the initial guard used "start >= bits", reading map out of bounds when bits is a multiple of BITS_PER_LONG. Allocate st_size + 1 and use ">=" for the loop guard. pthread_spin_init returns a positive errno on failure, but wd_blockpool_create/wd_mempool_create checked "if (ret < 0)" which was always false, and wd_soft_alloc_ctx did not check the return value at all, leaving spinlocks uninitialized. Use "if (ret)" to detect failure, check both spin_init calls in wd_soft_alloc_ctx, clean up on failure, and return -ret so callers can detect the error. hisi_qm_create_sglpool missed NULL check on hisi_qm_align_sgl and set sgl_num to i instead of i + 1 on failure, leaking the already-allocated sgl[i]. hisi_qm_get_hw_sgl, hisi_sec_cipher_send/_v3, cipher/digest/ aead recv and fill_zip_comp_sqe also leaked SGL/DMA resources or passed NULL to hardware on error paths. Add NULL checks, fix sgl_num, and recycle SGL entries on error paths. wd_*_poll_ctx in wd_ecc/rsa/dh/udma.c put recv_msg.tag (0 from zero-initialized recv_msg) back into the message pool on drv->recv failure, marking slot 0 as free even when in use and causing double-use or use-after-free. sm2_enc_parse in hisi_hpre.c leaked the second SQE and its DMA mappings when parse_second_sqe partially succeeded. Remove the wd_put_msg_to_pool call on recv failure and free the second SQE before jumping to free_first. wd_pool_init in wd_bmm.c allocated blk_array with malloc, leaving elements uninitialized and passing garbage blk/blk_dma to wd_iova_unmap on the error cleanup path. wd_comp_init_nolock in wd_comp.c called wd_alg_init_driver redundantly since the caller already invokes it, causing double initialization. Use calloc to zero-initialize blk_array and remove the redundant wd_alg_init_driver call. Signed-off-by: Weili Qian <qianweili@huawei.com> --- drv/hisi_comp.c | 7 ++++++- drv/hisi_hpre.c | 2 ++ drv/hisi_qm_udrv.c | 15 +++++++++++++-- drv/hisi_sec.c | 34 ++++++++++++++++++++-------------- drv/wd_drv.c | 16 ++++++++++++++-- wd.c | 3 ++- wd_bmm.c | 2 +- wd_comp.c | 6 ------ wd_dh.c | 2 -- wd_ecc.c | 2 -- wd_mempool.c | 6 +++--- wd_rsa.c | 2 -- wd_udma.c | 2 -- 13 files changed, 61 insertions(+), 38 deletions(-) diff --git a/drv/hisi_comp.c b/drv/hisi_comp.c index b798811..c1b83c3 100644 --- a/drv/hisi_comp.c +++ b/drv/hisi_comp.c @@ -1555,8 +1555,13 @@ static int fill_zip_comp_sqe(struct hisi_qp *qp, struct wd_comp_msg *msg, ops[alg_type].fill_alg(sqe); ret = ops[alg_type].fill_comp_level(sqe, msg->comp_lv); - if (unlikely(ret)) + if (unlikely(ret)) { + if (msg->mm_ops && !msg->mm_ops->sva_mode) + zip_mem_unmap(msg, sqe); + if (msg->req.data_fmt == WD_SGL_BUF) + free_hw_sgl((handle_t)qp, &msg->c_sgl, msg->mm_ops); return ret; + } ops[alg_type].fill_tag(sqe, msg->tag); diff --git a/drv/hisi_hpre.c b/drv/hisi_hpre.c index 70abe92..6d61fa4 100644 --- a/drv/hisi_hpre.c +++ b/drv/hisi_hpre.c @@ -2713,6 +2713,8 @@ static int sm2_enc_parse(handle_t h_qp, struct wd_ecc_msg *msg, ret = parse_second_sqe(h_qp, msg, &second); if (unlikely(ret)) { WD_ERR("failed to parse second BD, ret = %d!\n", ret); + if (second) + free_req(second); goto free_first; } diff --git a/drv/hisi_qm_udrv.c b/drv/hisi_qm_udrv.c index 6da9887..8617b10 100644 --- a/drv/hisi_qm_udrv.c +++ b/drv/hisi_qm_udrv.c @@ -803,6 +803,10 @@ handle_t hisi_qm_create_sglpool(__u32 sgl_num, __u32 sge_num, struct wd_mm_ops * sgl_pool->sgl_align[i] = hisi_qm_align_sgl(sgl_pool->sgl[i], sge_num, sgl_pool->mm_ops); + if (!sgl_pool->sgl_align[i]) { + sgl_pool->sgl_num = i + 1; + goto err_out; + } } sgl_pool->sgl_num = sgl_num; @@ -999,11 +1003,18 @@ void *hisi_qm_get_hw_sgl(handle_t sgl_pool, struct wd_datalist *sgl) ret = WD_ERR_PTR(-WD_EBUSY); goto err_out; } - if (mm_ops) + if (mm_ops) { cur->next_dma = (uintptr_t)mm_ops->iova_map(mm_ops->usr, next, sizeof(*next)); - else + if (!cur->next_dma) { + WD_ERR("invalid: iova_map for sgl chain failed!\n"); + hisi_qm_sgl_push(pool, next); + ret = WD_ERR_PTR(-WD_ENOMEM); + goto err_out; + } + } else { cur->next_dma = (uintptr_t)next; + } cur->next = next; cur = next; head->entry_sum_in_chain += pool->sge_num; diff --git a/drv/hisi_sec.c b/drv/hisi_sec.c index 10bb34e..df086d7 100644 --- a/drv/hisi_sec.c +++ b/drv/hisi_sec.c @@ -1439,22 +1439,25 @@ static int hisi_sec_cipher_send(handle_t ctx, void *wd_msg) ret = fill_cipher_bd2_addr(msg, &sqe); if (ret < 0) { WD_ERR("cipher map memory is err(%d)!\n", ret); - return ret; + goto put_sgl; } ret = hisi_qm_send(h_qp, &sqe, 1, &count); if (ret < 0) { if (ret != -WD_EBUSY) WD_ERR("cipher send sqe is err(%d)!\n", ret); - - if (msg->data_fmt == WD_SGL_BUF) - hisi_sec_put_sgl(h_qp, msg->alg_type, msg->in, - msg->out, msg->mm_ops); - destroy_cipher_bd2_addr(msg, &sqe); - return ret; + goto destroy_addr; } return 0; + +destroy_addr: + destroy_cipher_bd2_addr(msg, &sqe); +put_sgl: + if (msg->data_fmt == WD_SGL_BUF) + hisi_sec_put_sgl(h_qp, msg->alg_type, msg->in, + msg->out, msg->mm_ops); + return ret; } int hisi_sec_cipher_recv(handle_t ctx, void *wd_msg) @@ -1735,22 +1738,25 @@ static int hisi_sec_cipher_send_v3(handle_t ctx, void *wd_msg) ret = fill_cipher_bd3_addr(msg, &sqe); if (ret < 0) { WD_ERR("cipher map memory is err(%d)!\n", ret); - return ret; + goto put_sgl; } ret = hisi_qm_send(h_qp, &sqe, 1, &count); if (ret < 0) { if (ret != -WD_EBUSY) WD_ERR("cipher send sqe is err(%d)!\n", ret); - - if (msg->data_fmt == WD_SGL_BUF) - hisi_sec_put_sgl(h_qp, msg->alg_type, msg->in, - msg->out, msg->mm_ops); - destroy_cipher_bd3_addr(msg, &sqe); - return ret; + goto destroy_addr; } return 0; + +destroy_addr: + destroy_cipher_bd3_addr(msg, &sqe); +put_sgl: + if (msg->data_fmt == WD_SGL_BUF) + hisi_sec_put_sgl(h_qp, msg->alg_type, msg->in, + msg->out, msg->mm_ops); + return ret; } static void parse_cipher_bd3(struct hisi_qp *qp, struct hisi_sec_sqe3 *sqe, diff --git a/drv/wd_drv.c b/drv/wd_drv.c index 08014dd..4bac551 100644 --- a/drv/wd_drv.c +++ b/drv/wd_drv.c @@ -11,6 +11,7 @@ int wd_soft_alloc_ctx(char *alg_name, void *params, handle_t *ctx) { struct wd_soft_ctx *sfctx; + int ret; if (!params || !ctx) { WD_ERR("invalid: params, or ctx is NULL!\n"); @@ -27,8 +28,19 @@ int wd_soft_alloc_ctx(char *alg_name, void *params, handle_t *ctx) /* Initialize as software context */ sfctx->fd = -1; sfctx->ctx_type = UADK_ALG_SOFT; - pthread_spin_init(&sfctx->slock, PTHREAD_PROCESS_PRIVATE); - pthread_spin_init(&sfctx->rlock, PTHREAD_PROCESS_PRIVATE); + ret = pthread_spin_init(&sfctx->slock, PTHREAD_PROCESS_PRIVATE); + if (ret) { + WD_ERR("failed to init slock!\n"); + free(sfctx); + return -ret; + } + ret = pthread_spin_init(&sfctx->rlock, PTHREAD_PROCESS_PRIVATE); + if (ret) { + WD_ERR("failed to init rlock!\n"); + pthread_spin_destroy(&sfctx->slock); + free(sfctx); + return -ret; + } /* Return context handle */ *ctx = (handle_t)sfctx; diff --git a/wd.c b/wd.c index f973c70..bd0a3aa 100644 --- a/wd.c +++ b/wd.c @@ -114,11 +114,12 @@ static void wd_parse_log_level(void) goto close_file; } - file_contents = malloc(file_info.st_size); + file_contents = malloc(file_info.st_size + 1); if (!file_contents) { WD_ERR("failed to get file contents memory.\n"); goto close_file; } + file_contents[file_info.st_size] = '\0'; while (fscanf(in_file, " %[^\n ] ", file_contents) != EOF) { if (!strcmp("local5.debug", file_contents)) diff --git a/wd_bmm.c b/wd_bmm.c index 811afa2..e393e59 100644 --- a/wd_bmm.c +++ b/wd_bmm.c @@ -707,7 +707,7 @@ static int wd_pool_init(struct wd_blkpool *p) } /* Allocate block array */ - p->blk_array = (struct wd_blk_hd *)malloc(act_num * sizeof(struct wd_blk_hd)); + p->blk_array = (struct wd_blk_hd *)calloc(act_num, sizeof(struct wd_blk_hd)); if (!p->blk_array) { WD_ERR("Failed to allocate block array.\n"); return -WD_ENOMEM; diff --git a/wd_comp.c b/wd_comp.c index 35af141..523a189 100644 --- a/wd_comp.c +++ b/wd_comp.c @@ -156,14 +156,8 @@ static int wd_comp_init_nolock(struct wd_ctx_config *config, struct wd_sched *sc if (ret < 0) goto out_clear_sched; - ret = wd_alg_init_driver(&wd_comp_setting.config); - if (ret) - goto out_clear_pool; - return 0; -out_clear_pool: - wd_uninit_async_request_pool(&wd_comp_setting.pool); out_clear_sched: wd_clear_sched(&wd_comp_setting.sched); out_clear_ctx_config: diff --git a/wd_dh.c b/wd_dh.c index 8026fd6..f9958b2 100644 --- a/wd_dh.c +++ b/wd_dh.c @@ -520,8 +520,6 @@ int wd_dh_poll_ctx(__u32 idx, __u32 expt, __u32 *count) } else if (unlikely(ret)) { WD_ERR("failed to async recv, ret = %d!\n", ret); *count = rcv_cnt; - wd_put_msg_to_pool(&wd_dh_setting.pool, idx, - rcv_msg.tag); return ret; } rcv_cnt++; diff --git a/wd_ecc.c b/wd_ecc.c index 4b141c4..679a3fb 100644 --- a/wd_ecc.c +++ b/wd_ecc.c @@ -2519,8 +2519,6 @@ int wd_ecc_poll_ctx(__u32 idx, __u32 expt, __u32 *count) } else if (ret < 0) { WD_ERR("failed to async recv, ret = %d!\n", ret); *count = rcv_cnt; - wd_put_msg_to_pool(&wd_ecc_setting.pool, idx, - recv_msg.tag); return ret; } rcv_cnt++; diff --git a/wd_mempool.c b/wd_mempool.c index 3ce9ef0..4081130 100644 --- a/wd_mempool.c +++ b/wd_mempool.c @@ -239,7 +239,7 @@ static unsigned long _find_next_bit(unsigned long *map, unsigned long bits, while (!tmp) { start += BITS_PER_LONG; - if (start > bits) + if (start >= bits) return bits; tmp = map[start / BITS_PER_LONG]; @@ -561,7 +561,7 @@ handle_t wd_blockpool_create(handle_t mempool, size_t block_size, bp->free_block_num = block_num; bp->mp = mp; ret = pthread_spin_init(&bp->lock, PTHREAD_PROCESS_PRIVATE); - if (ret < 0) + if (ret) goto err_free_bp; ret = alloc_mem_from_mempool(mp, bp); @@ -910,7 +910,7 @@ handle_t wd_mempool_create(size_t size, int node) mp->size = tmp; mp->blk_size = WD_MEMPOOL_BLOCK_SIZE; ret = pthread_spin_init(&mp->lock, PTHREAD_PROCESS_PRIVATE); - if (ret < 0) + if (ret) goto free_pool; ret = alloc_mem_from_hugepage(mp); diff --git a/wd_rsa.c b/wd_rsa.c index 59c230d..539285d 100644 --- a/wd_rsa.c +++ b/wd_rsa.c @@ -583,8 +583,6 @@ int wd_rsa_poll_ctx(__u32 idx, __u32 expt, __u32 *count) return ret; } else if (ret < 0) { WD_ERR("failed to async recv, ret = %d!\n", ret); - wd_put_msg_to_pool(&wd_rsa_setting.pool, idx, - recv_msg.tag); return ret; } rcv_cnt++; diff --git a/wd_udma.c b/wd_udma.c index 59841bb..b92e75b 100644 --- a/wd_udma.c +++ b/wd_udma.c @@ -337,8 +337,6 @@ static int wd_udma_poll_ctx(__u32 idx, __u32 expt, __u32 *count) } else if (unlikely(ret)) { WD_ERR("failed to async recv, ret = %d!\n", ret); *count = rcv_cnt; - wd_put_msg_to_pool(&wd_udma_setting.pool, idx, - rcv_msg.tag); return ret; } rcv_cnt++; -- 2.28.0.windows.1