RDMA/rtrs-clt: Fix possible double free in error case
[ Upstream commit 8700af2cc18c919b2a83e74e0479038fd113c15d ] Callback function rtrs_clt_dev_release() for put_device() calls kfree(clt) to free memory. We shouldn't call kfree(clt) again, and we can't use the clt after kfree too. Replace device_register() with device_initialize() and device_add() so that dev_set_name can() be used appropriately. Move mutex_destroy() to the release function so it can be called in the alloc_clt err path. Fixes: eab098246625 ("RDMA/rtrs-clt: Refactor the failure cases in alloc_clt") Link: https://lore.kernel.org/r/20220217030929.323849-1-haris.iqbal@ionos.com Reported-by: Miaoqian Lin <linmq006@gmail.com> Signed-off-by: Md Haris Iqbal <haris.iqbal@ionos.com> Reviewed-by: Jack Wang <jinpu.wang@ionos.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
dc64aa4c7d
commit
8260f1800f
@@ -2540,6 +2540,8 @@ static void rtrs_clt_dev_release(struct device *dev)
|
|||||||
{
|
{
|
||||||
struct rtrs_clt *clt = container_of(dev, struct rtrs_clt, dev);
|
struct rtrs_clt *clt = container_of(dev, struct rtrs_clt, dev);
|
||||||
|
|
||||||
|
mutex_destroy(&clt->paths_ev_mutex);
|
||||||
|
mutex_destroy(&clt->paths_mutex);
|
||||||
kfree(clt);
|
kfree(clt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2571,6 +2573,8 @@ static struct rtrs_clt *alloc_clt(const char *sessname, size_t paths_num,
|
|||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clt->dev.class = rtrs_clt_dev_class;
|
||||||
|
clt->dev.release = rtrs_clt_dev_release;
|
||||||
uuid_gen(&clt->paths_uuid);
|
uuid_gen(&clt->paths_uuid);
|
||||||
INIT_LIST_HEAD_RCU(&clt->paths_list);
|
INIT_LIST_HEAD_RCU(&clt->paths_list);
|
||||||
clt->paths_num = paths_num;
|
clt->paths_num = paths_num;
|
||||||
@@ -2588,43 +2592,41 @@ static struct rtrs_clt *alloc_clt(const char *sessname, size_t paths_num,
|
|||||||
init_waitqueue_head(&clt->permits_wait);
|
init_waitqueue_head(&clt->permits_wait);
|
||||||
mutex_init(&clt->paths_ev_mutex);
|
mutex_init(&clt->paths_ev_mutex);
|
||||||
mutex_init(&clt->paths_mutex);
|
mutex_init(&clt->paths_mutex);
|
||||||
|
device_initialize(&clt->dev);
|
||||||
|
|
||||||
clt->dev.class = rtrs_clt_dev_class;
|
|
||||||
clt->dev.release = rtrs_clt_dev_release;
|
|
||||||
err = dev_set_name(&clt->dev, "%s", sessname);
|
err = dev_set_name(&clt->dev, "%s", sessname);
|
||||||
if (err)
|
if (err)
|
||||||
goto err;
|
goto err_put;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Suppress user space notification until
|
* Suppress user space notification until
|
||||||
* sysfs files are created
|
* sysfs files are created
|
||||||
*/
|
*/
|
||||||
dev_set_uevent_suppress(&clt->dev, true);
|
dev_set_uevent_suppress(&clt->dev, true);
|
||||||
err = device_register(&clt->dev);
|
err = device_add(&clt->dev);
|
||||||
if (err) {
|
if (err)
|
||||||
put_device(&clt->dev);
|
goto err_put;
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
clt->kobj_paths = kobject_create_and_add("paths", &clt->dev.kobj);
|
clt->kobj_paths = kobject_create_and_add("paths", &clt->dev.kobj);
|
||||||
if (!clt->kobj_paths) {
|
if (!clt->kobj_paths) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto err_dev;
|
goto err_del;
|
||||||
}
|
}
|
||||||
err = rtrs_clt_create_sysfs_root_files(clt);
|
err = rtrs_clt_create_sysfs_root_files(clt);
|
||||||
if (err) {
|
if (err) {
|
||||||
kobject_del(clt->kobj_paths);
|
kobject_del(clt->kobj_paths);
|
||||||
kobject_put(clt->kobj_paths);
|
kobject_put(clt->kobj_paths);
|
||||||
goto err_dev;
|
goto err_del;
|
||||||
}
|
}
|
||||||
dev_set_uevent_suppress(&clt->dev, false);
|
dev_set_uevent_suppress(&clt->dev, false);
|
||||||
kobject_uevent(&clt->dev.kobj, KOBJ_ADD);
|
kobject_uevent(&clt->dev.kobj, KOBJ_ADD);
|
||||||
|
|
||||||
return clt;
|
return clt;
|
||||||
err_dev:
|
err_del:
|
||||||
device_unregister(&clt->dev);
|
device_del(&clt->dev);
|
||||||
err:
|
err_put:
|
||||||
free_percpu(clt->pcpu_path);
|
free_percpu(clt->pcpu_path);
|
||||||
kfree(clt);
|
put_device(&clt->dev);
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2643,9 +2645,10 @@ static void free_clt(struct rtrs_clt *clt)
|
|||||||
wait_for_inflight_permits(clt);
|
wait_for_inflight_permits(clt);
|
||||||
free_permits(clt);
|
free_permits(clt);
|
||||||
free_percpu(clt->pcpu_path);
|
free_percpu(clt->pcpu_path);
|
||||||
mutex_destroy(&clt->paths_ev_mutex);
|
|
||||||
mutex_destroy(&clt->paths_mutex);
|
/*
|
||||||
/* release callback will free clt in last put */
|
* release callback will free clt and destroy mutexes in last put
|
||||||
|
*/
|
||||||
device_unregister(&clt->dev);
|
device_unregister(&clt->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user