Skip to content

Commit b592211

Browse files
committed
dm mpath: fix attached_handler_name leak and dangling hw_handler_name pointer
Commit e8f74a0 ("dm mpath: eliminate need to use scsi_device_from_queue") introduced 2 regressions: 1) memory leak occurs if attached_handler_name is not assigned to m->hw_handler_name 2) m->hw_handler_name can become a dangling pointer if the RETAIN_ATTACHED_HW_HANDLER flag is set and scsi_dh_attach() returns -EBUSY. Fix both of these by clearing 'attached_handler_name' pointer passed to setup_scsi_dh() after it is assigned to m->hw_handler_name. And if setup_scsi_dh() doesn't consume 'attached_handler_name' parse_path() will kfree() it. Fixes: e8f74a0 ("dm mpath: eliminate need to use scsi_device_from_queue") Cc: stable@vger.kernel.org # 4.16+ Reported-by: Bart Van Assche <bvanassche@acm.org> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
1 parent 013ad04 commit b592211

File tree

1 file changed

+8
-6
lines changed

1 file changed

+8
-6
lines changed

drivers/md/dm-mpath.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -806,19 +806,19 @@ static int parse_path_selector(struct dm_arg_set *as, struct priority_group *pg,
806806
}
807807

808808
static int setup_scsi_dh(struct block_device *bdev, struct multipath *m,
809-
const char *attached_handler_name, char **error)
809+
const char **attached_handler_name, char **error)
810810
{
811811
struct request_queue *q = bdev_get_queue(bdev);
812812
int r;
813813

814814
if (test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags)) {
815815
retain:
816-
if (attached_handler_name) {
816+
if (*attached_handler_name) {
817817
/*
818818
* Clear any hw_handler_params associated with a
819819
* handler that isn't already attached.
820820
*/
821-
if (m->hw_handler_name && strcmp(attached_handler_name, m->hw_handler_name)) {
821+
if (m->hw_handler_name && strcmp(*attached_handler_name, m->hw_handler_name)) {
822822
kfree(m->hw_handler_params);
823823
m->hw_handler_params = NULL;
824824
}
@@ -830,7 +830,8 @@ static int setup_scsi_dh(struct block_device *bdev, struct multipath *m,
830830
* handler instead of the original table passed in.
831831
*/
832832
kfree(m->hw_handler_name);
833-
m->hw_handler_name = attached_handler_name;
833+
m->hw_handler_name = *attached_handler_name;
834+
*attached_handler_name = NULL;
834835
}
835836
}
836837

@@ -867,7 +868,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
867868
struct pgpath *p;
868869
struct multipath *m = ti->private;
869870
struct request_queue *q;
870-
const char *attached_handler_name;
871+
const char *attached_handler_name = NULL;
871872

872873
/* we need at least a path arg */
873874
if (as->argc < 1) {
@@ -890,7 +891,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
890891
attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL);
891892
if (attached_handler_name || m->hw_handler_name) {
892893
INIT_DELAYED_WORK(&p->activate_path, activate_path_work);
893-
r = setup_scsi_dh(p->path.dev->bdev, m, attached_handler_name, &ti->error);
894+
r = setup_scsi_dh(p->path.dev->bdev, m, &attached_handler_name, &ti->error);
894895
if (r) {
895896
dm_put_device(ti, p->path.dev);
896897
goto bad;
@@ -905,6 +906,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
905906

906907
return p;
907908
bad:
909+
kfree(attached_handler_name);
908910
free_pgpath(p);
909911
return ERR_PTR(r);
910912
}

0 commit comments

Comments
 (0)