From 09f29f9266382802ce83053dcfddb83d0c5176be Mon Sep 17 00:00:00 2001 From: dujunbao <14829755+du-junbao@user.noreply.gitee.com> Date: Tue, 22 Sep 2026 21:52:19 +0800 Subject: [PATCH] ub: udma: free the tp active buffers with kfree() instead of kfree_rcu() udma_ctrlq_check_tp_status() and udma_ctrlq_check_tp_active() each declare a two-member helper struct on the stack - a pointer plus a struct rcu_head - and then hand its address to kfree_rcu(). The grace-period callback therefore ends up calling kfree() on a stack address, which is not a slab object, while the buffers that were actually allocated, the request copy and the response buffer, are never freed at all. The message payload is consumed synchronously: ubase_ctrlq_send_msg() copies msg->in into the ctrlq ring (or to the IO memory for the command queue) before it returns and the handler passes need_resp = 0, so nothing refers to either buffer afterwards. Drop the stack helper structs: keep the allocated request copy in a plain pointer and release both buffers with kfree(), including on the allocation failure path. Fixes: c9b3a6e6a823 ("ub: udma: fix a bug related to free rcu mem") --- drivers/ub/urma/hw/udma/udma_eq.c | 36 +++++++++++-------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/drivers/ub/urma/hw/udma/udma_eq.c b/drivers/ub/urma/hw/udma/udma_eq.c index 4fa9747cbc2d..9cd82dd2613a 100644 --- a/drivers/ub/urma/hw/udma/udma_eq.c +++ b/drivers/ub/urma/hw/udma/udma_eq.c @@ -707,12 +707,7 @@ static int udma_ctrlq_check_tp_status(struct udma_dev *udev, void *data, uint16_ uint32_t *rsp_info_len) { #define UDMA_CTRLQ_CHECK_TP_OFFSET 0xFF -struct udma_tp_active_req_info { - struct udma_ctrlq_check_tp_active_req_info *info; - struct rcu_head rcu; -}; - - struct udma_tp_active_req_info tp_active_req; + struct udma_ctrlq_check_tp_active_req_info *tp_active_req; uint32_t req_info_len; uint32_t tp_num; uint32_t i; @@ -724,28 +719,28 @@ struct udma_tp_active_req_info { dev_err(udev->dev, "msg param num(%u) is invalid.\n", tp_num); return -EINVAL; } - tp_active_req.info = kzalloc(req_info_len, GFP_KERNEL); - if (!tp_active_req.info) + tp_active_req = kzalloc(req_info_len, GFP_KERNEL); + if (!tp_active_req) return -ENOMEM; - memcpy(tp_active_req.info, data, req_info_len); + memcpy(tp_active_req, data, req_info_len); *rsp_info_len = sizeof(struct udma_ctrlq_check_tp_active_rsp_info) + sizeof(struct udma_ctrlq_check_tp_active_rsp_data) * tp_num; *rsp_info = kzalloc(*rsp_info_len, GFP_KERNEL); if (!(*rsp_info)) { *rsp_info_len = 0; - kfree_rcu(&tp_active_req, rcu); + kfree(tp_active_req); return -ENOMEM; } rcu_read_lock(); - for (i = 0; i < tp_active_req.info->num; i++) { - if (find_vpid(tp_active_req.info->data[i].pid_flag)) + for (i = 0; i < tp_active_req->num; i++) { + if (find_vpid(tp_active_req->data[i].pid_flag)) (*rsp_info)->data[i].result = UDMA_CTRLQ_TPID_IN_USE; else (*rsp_info)->data[i].result = UDMA_CTRLQ_TPID_EXITED; - (*rsp_info)->data[i].tp_id = tp_active_req.info->data[i].tp_id; + (*rsp_info)->data[i].tp_id = tp_active_req->data[i].tp_id; } (*rsp_info)->num = tp_num; rcu_read_unlock(); @@ -754,7 +749,7 @@ struct udma_tp_active_req_info { udma_dfx_ctx_print(udev, "udma check tp active", (*rsp_info)->data[0].tp_id, *rsp_info_len / sizeof(uint32_t), (uint32_t *)(*rsp_info)); - kfree_rcu(&tp_active_req, rcu); + kfree(tp_active_req); return 0; } @@ -778,12 +773,7 @@ static int udma_ctrlq_check_tp_active(struct auxiliary_device *adev, uint8_t service_ver, void *data, uint16_t len, uint16_t seq) { -struct udma_tp_active_rsq_info { - struct udma_ctrlq_check_tp_active_rsp_info *info; - struct rcu_head rcu; -}; - - struct udma_tp_active_rsq_info tp_active_rsq; + struct udma_ctrlq_check_tp_active_rsp_info *rsp_info = NULL; struct udma_dev *udev = get_udma_dev(adev); struct ubase_ctrlq_msg msg = {}; uint32_t rsp_info_len = 0; @@ -796,7 +786,7 @@ struct udma_tp_active_rsq_info { ret = udma_ctrlq_check_tp_active_param(udev, data, len); if (ret == 0) { - ret = udma_ctrlq_check_tp_status(udev, data, len, &tp_active_rsq.info, + ret = udma_ctrlq_check_tp_status(udev, data, len, &rsp_info, &rsp_info_len); if (ret) dev_err(udev->dev, "check tp status failed, ret(%d).\n", ret); @@ -808,7 +798,7 @@ struct udma_tp_active_rsq_info { msg.need_resp = 0; msg.is_resp = 1; msg.in_size = (uint16_t)rsp_info_len; - msg.in = (void *)tp_active_rsq.info; + msg.in = (void *)rsp_info; msg.resp_seq = seq; msg.resp_ret = (uint8_t)(-ret); @@ -816,7 +806,7 @@ struct udma_tp_active_rsq_info { if (ret) dev_err(udev->dev, "send check tp active ctrlq msg failed, ret(%d).\n", ret); - kfree_rcu(&tp_active_rsq, rcu); + kfree(rsp_info); return ret; } -- Gitee