From: Weili Qian <qianweili@huawei.com> 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. Signed-off-by: Weili Qian <qianweili@huawei.com> --- drv/hisi_comp.c | 7 ++++++- drv/hisi_qm_udrv.c | 15 +++++++++++++-- drv/hisi_sec.c | 34 ++++++++++++++++++++-------------- 3 files changed, 39 insertions(+), 17 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_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, -- 2.50.1.windows.1