Commit 54552708 authored by wenglianfa's avatar wenglianfa Committed by Juan Zhou
Browse files

RDMA/hns: Fix scc_param delay_work to execute after sysfs shutdown

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: 41da9cd8 ("RDMA/hns: Support congestion control algorithm parameter configuration")
Signed-off-by: default avatarwenglianfa <wenglianfa@huawei.com>
parent ce3f7c20
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1453,8 +1453,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);
@@ -1462,4 +1460,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 */
+7 −2
Original line number Diff line number Diff line
@@ -1449,16 +1449,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);

@@ -1488,8 +1493,8 @@ int hns_roce_init(struct hns_roce_dev *hr_dev)

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)
+14 −17
Original line number Diff line number Diff line
@@ -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);
}