Skip to content

Commit fba2f22

Browse files
Rongronggg91Naim
authored andcommitted
platform/x86: lenovo-wmi-other: Balance IDA id allocation and free
Currently, the IDA id is only freed on wmi-other device removal or failure to create firmware-attributes device, kset, or attributes. It leaks IDA ids if the wmi-other device is bound multiple times, as the unbind callback never frees the previously allocated IDA id. Additionally, if the wmi-other device has failed to create a firmware-attributes device before it gets removed, the wmi-device removal callback double frees the same IDA id. These bugs were found by sashiko.dev [1]. Fix them by moving ida_free() into lwmi_om_fw_attr_remove() so it is balanced with ida_alloc() in lwmi_om_fw_attr_add(). With them fixed, properly set and utilize the validity of priv->ida_id to balance firmware-attributes registration and removal, without relying on propagating the registration error to the component framework, which is more reliable and aligns with the hwmon device registration and removal sequences. No functional change intended. Fixes: edc4b18 ("platform/x86: Add Lenovo Other Mode WMI Driver") Cc: stable@vger.kernel.org Link: https://sashiko.dev/#/patchset/20260331181208.421552-1-derekjohn.clark%40gmail.com [1] Signed-off-by: Rong Zhang <i@rong.moe>
1 parent bc705a5 commit fba2f22

1 file changed

Lines changed: 20 additions & 14 deletions

File tree

drivers/platform/x86/lenovo/wmi-other.c

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -957,17 +957,17 @@ static struct capdata01_attr_group cd01_attr_groups[] = {
957957
/**
958958
* lwmi_om_fw_attr_add() - Register all firmware_attributes_class members
959959
* @priv: The Other Mode driver data.
960-
*
961-
* Return: Either 0, or an error code.
962960
*/
963-
static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
961+
static void lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
964962
{
965963
unsigned int i;
966964
int err;
967965

968966
priv->ida_id = ida_alloc(&lwmi_om_ida, GFP_KERNEL);
969-
if (priv->ida_id < 0)
970-
return priv->ida_id;
967+
if (priv->ida_id < 0) {
968+
err = priv->ida_id;
969+
goto err;
970+
}
971971

972972
priv->fw_attr_dev = device_create(&firmware_attributes_class, NULL,
973973
MKDEV(0, 0), NULL, "%s-%u",
@@ -993,7 +993,7 @@ static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
993993

994994
cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev;
995995
}
996-
return 0;
996+
return;
997997

998998
err_remove_groups:
999999
while (i--)
@@ -1007,7 +1007,12 @@ static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
10071007

10081008
err_free_ida:
10091009
ida_free(&lwmi_om_ida, priv->ida_id);
1010-
return err;
1010+
1011+
err:
1012+
priv->ida_id = -EIDRM;
1013+
1014+
dev_warn(&priv->wdev->dev,
1015+
"failed to register firmware-attributes device: %d\n", err);
10111016
}
10121017

10131018
/**
@@ -1016,12 +1021,17 @@ static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
10161021
*/
10171022
static void lwmi_om_fw_attr_remove(struct lwmi_om_priv *priv)
10181023
{
1024+
if (priv->ida_id < 0)
1025+
return;
1026+
10191027
for (unsigned int i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++)
10201028
sysfs_remove_group(&priv->fw_attr_kset->kobj,
10211029
cd01_attr_groups[i].attr_group);
10221030

10231031
kset_unregister(priv->fw_attr_kset);
10241032
device_unregister(priv->fw_attr_dev);
1033+
ida_free(&lwmi_om_ida, priv->ida_id);
1034+
priv->ida_id = -EIDRM;
10251035
}
10261036

10271037
/* ======== Self (master: lenovo-wmi-other) ======== */
@@ -1063,7 +1073,9 @@ static int lwmi_om_master_bind(struct device *dev)
10631073

10641074
lwmi_om_fan_info_collect_cd00(priv);
10651075

1066-
return lwmi_om_fw_attr_add(priv);
1076+
lwmi_om_fw_attr_add(priv);
1077+
1078+
return 0;
10671079
}
10681080

10691081
/**
@@ -1115,13 +1127,7 @@ static int lwmi_other_probe(struct wmi_device *wdev, const void *context)
11151127

11161128
static void lwmi_other_remove(struct wmi_device *wdev)
11171129
{
1118-
struct lwmi_om_priv *priv = dev_get_drvdata(&wdev->dev);
1119-
11201130
component_master_del(&wdev->dev, &lwmi_om_master_ops);
1121-
1122-
/* No IDA to free if the driver is never bound to its components. */
1123-
if (priv->ida_id >= 0)
1124-
ida_free(&lwmi_om_ida, priv->ida_id);
11251131
}
11261132

11271133
static const struct wmi_device_id lwmi_other_id_table[] = {

0 commit comments

Comments
 (0)