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:
Md Haris Iqbal
2022-02-17 04:09:28 +01:00
committed by Greg Kroah-Hartman
parent dc64aa4c7d
commit 8260f1800f

View File

@@ -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);
} }