Skip to content

Commit f67fbbf

Browse files
lgs2513gregkh
authored andcommitted
IB/mlx4: Fix refcount leak in add_port() error path
[ Upstream commit 9a8826f ] After kobject_init_and_add(), the lifetime of the embedded struct kobject is expected to be managed through the kobject core reference counting. In add_port(), failure paths after kobject_init_and_add() must not free struct mlx4_port directly, because the embedded kobject is then managed by the kobject core. Freeing it directly leaves the kobject reference counting unbalanced and can lead to incorrect lifetime handling. Allocate the pkey and gid attribute arrays before kobject_init_and_add(), so failures before kobject initialization can be handled by directly freeing the allocated memory. Once kobject_init_and_add() has been called, unwind later failures by removing any successfully created sysfs groups, calling kobject_del(), and then releasing the embedded kobject with kobject_put(). Fixes: c1e7e46 ("IB/mlx4: Add iov directory in sysfs under the ib device") Link: https://patch.msgid.link/r/20260518021910.972900-1-lgs201920130244@gmail.com Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent e59a6aa commit f67fbbf

1 file changed

Lines changed: 27 additions & 18 deletions

File tree

drivers/infiniband/hw/mlx4/sysfs.c

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -638,55 +638,64 @@ static int add_port(struct mlx4_ib_dev *dev, int port_num, int slave)
638638
p->port_num = port_num;
639639
p->slave = slave;
640640

641-
ret = kobject_init_and_add(&p->kobj, &port_type,
642-
kobject_get(dev->dev_ports_parent[slave]),
643-
"%d", port_num);
644-
if (ret)
645-
goto err_alloc;
646-
647641
p->pkey_group.name = "pkey_idx";
648642
p->pkey_group.attrs =
649643
alloc_group_attrs(show_port_pkey,
650644
is_eth ? NULL : store_port_pkey,
651645
dev->dev->caps.pkey_table_len[port_num]);
652646
if (!p->pkey_group.attrs) {
653647
ret = -ENOMEM;
654-
goto err_alloc;
648+
goto err_free_port;
655649
}
656650

657-
ret = sysfs_create_group(&p->kobj, &p->pkey_group);
658-
if (ret)
659-
goto err_free_pkey;
660-
661651
p->gid_group.name = "gid_idx";
662652
p->gid_group.attrs = alloc_group_attrs(show_port_gid_idx, NULL, 1);
663653
if (!p->gid_group.attrs) {
664654
ret = -ENOMEM;
665655
goto err_free_pkey;
666656
}
667657

658+
ret = kobject_init_and_add(&p->kobj, &port_type,
659+
kobject_get(dev->dev_ports_parent[slave]),
660+
"%d", port_num);
661+
if (ret)
662+
goto err_put;
663+
664+
ret = sysfs_create_group(&p->kobj, &p->pkey_group);
665+
if (ret)
666+
goto err_del;
667+
668668
ret = sysfs_create_group(&p->kobj, &p->gid_group);
669669
if (ret)
670-
goto err_free_gid;
670+
goto err_remove_pkey;
671671

672672
ret = add_vf_smi_entries(p);
673673
if (ret)
674-
goto err_free_gid;
674+
goto err_remove_gid;
675675

676676
list_add_tail(&p->kobj.entry, &dev->pkeys.pkey_port_list[slave]);
677677
return 0;
678678

679-
err_free_gid:
680-
kfree(p->gid_group.attrs[0]);
681-
kfree(p->gid_group.attrs);
679+
err_remove_gid:
680+
sysfs_remove_group(&p->kobj, &p->gid_group);
681+
682+
err_remove_pkey:
683+
sysfs_remove_group(&p->kobj, &p->pkey_group);
684+
685+
err_del:
686+
kobject_del(&p->kobj);
687+
688+
err_put:
689+
kobject_put(dev->dev_ports_parent[slave]);
690+
kobject_put(&p->kobj);
691+
return ret;
682692

683693
err_free_pkey:
684694
for (i = 0; i < dev->dev->caps.pkey_table_len[port_num]; ++i)
685695
kfree(p->pkey_group.attrs[i]);
686696
kfree(p->pkey_group.attrs);
687697

688-
err_alloc:
689-
kobject_put(dev->dev_ports_parent[slave]);
698+
err_free_port:
690699
kfree(p);
691700
return ret;
692701
}

0 commit comments

Comments
 (0)