From: wenglianfa wenglianfa@huawei.com
driver inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9GZX2
----------------------------------------------------------------------
After sysfs is disabled, scc delay_work may continue to be executed, causing the UAF problem. To fix it, cancel_delayde_work_sync() is introduced to ensure that scc delay_work is canceled or executed.
Fixes: 41da9cd8456d ("RDMA/hns: Support congestion control algorithm parameter configuration") Signed-off-by: wenglianfa wenglianfa@huawei.com --- drivers/infiniband/hw/hns/hns_roce_device.h | 4 +-- drivers/infiniband/hw/hns/hns_roce_main.c | 9 ++++-- drivers/infiniband/hw/hns/hns_roce_sysfs.c | 31 ++++++++++----------- 3 files changed, 23 insertions(+), 21 deletions(-)
diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 538e3ed03..80870c278 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -1452,8 +1452,6 @@ struct hns_user_mmap_entry * hns_roce_user_mmap_entry_insert(struct ib_ucontext *ucontext, u64 address, size_t length, enum hns_roce_mmap_type mmap_type); -void hns_roce_register_sysfs(struct hns_roce_dev *hr_dev); -void hns_roce_unregister_sysfs(struct hns_roce_dev *hr_dev); void hns_roce_add_unfree_umem(struct hns_roce_user_db_page *user_page, struct hns_roce_dev *hr_dev); void hns_roce_free_unfree_umem(struct hns_roce_dev *hr_dev); @@ -1461,4 +1459,6 @@ void hns_roce_add_unfree_mtr(struct hns_roce_mtr_node *pos, struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr); void hns_roce_free_unfree_mtr(struct hns_roce_dev *hr_dev); +int hns_roce_alloc_scc_param(struct hns_roce_dev *hr_dev); +void hns_roce_dealloc_scc_param(struct hns_roce_dev *hr_dev); #endif /* _HNS_ROCE_DEVICE_H */ diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 992e6dfaa..ab43b6688 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -1444,16 +1444,21 @@ int hns_roce_init(struct hns_roce_dev *hr_dev) } }
+ ret = hns_roce_alloc_scc_param(hr_dev); + if (ret) + dev_err(hr_dev->dev, "alloc scc param failed, ret = %d!\n", + ret); + ret = hns_roce_register_device(hr_dev); if (ret) goto error_failed_register_device;
- hns_roce_register_sysfs(hr_dev); hns_roce_register_debugfs(hr_dev);
return 0;
error_failed_register_device: + hns_roce_dealloc_scc_param(hr_dev); if (hr_dev->hw->hw_exit) hr_dev->hw->hw_exit(hr_dev);
@@ -1483,8 +1488,8 @@ error_failed_alloc_dfx_cnt:
void hns_roce_exit(struct hns_roce_dev *hr_dev, bool bond_cleanup) { - hns_roce_unregister_sysfs(hr_dev); hns_roce_unregister_device(hr_dev, bond_cleanup); + hns_roce_dealloc_scc_param(hr_dev); hns_roce_unregister_debugfs(hr_dev);
if (hr_dev->hw->hw_exit) diff --git a/drivers/infiniband/hw/hns/hns_roce_sysfs.c b/drivers/infiniband/hw/hns/hns_roce_sysfs.c index a9708d28a..110d558a5 100644 --- a/drivers/infiniband/hw/hns/hns_roce_sysfs.c +++ b/drivers/infiniband/hw/hns/hns_roce_sysfs.c @@ -33,7 +33,7 @@ static void get_default_scc_param(struct hns_roce_dev *hr_dev) } }
-static int alloc_scc_param(struct hns_roce_dev *hr_dev) +int hns_roce_alloc_scc_param(struct hns_roce_dev *hr_dev) { struct hns_roce_scc_param *scc_param; int i; @@ -56,6 +56,19 @@ static int alloc_scc_param(struct hns_roce_dev *hr_dev)
return 0; } +void hns_roce_dealloc_scc_param(struct hns_roce_dev *hr_dev) +{ + int i; + + if (!hr_dev->scc_param) + return; + + for (i = 0; i < HNS_ROCE_SCC_ALGO_TOTAL; i++) + cancel_delayed_work_sync(&hr_dev->scc_param[i].scc_cfg_dwork); + + kvfree(hr_dev->scc_param); + hr_dev->scc_param = NULL; +}
struct hns_port_cc_attr { struct ib_port_attribute port_attr; @@ -328,19 +341,3 @@ const struct attribute_group *hns_attr_port_groups[] = { &dip_cc_param_group, NULL, }; - -void hns_roce_register_sysfs(struct hns_roce_dev *hr_dev) -{ - int ret; - - ret = alloc_scc_param(hr_dev); - if (ret) - dev_err(hr_dev->dev, "alloc scc param failed, ret = %d!\n", - ret); -} - -void hns_roce_unregister_sysfs(struct hns_roce_dev *hr_dev) -{ - if (hr_dev->scc_param) - kvfree(hr_dev->scc_param); -}