Message ID | 20230415160734.70475-5-hdegoede@redhat.com |
---|---|
State | Accepted |
Commit | 4d5c129d6c8993fe96e9ae712141eedcb9ca68c2 |
Headers | show |
Series | power: supply: Fix external_power_changed race in several drivers | expand |
On 4/16/2023 12:07 AM, Hans de Goede wrote: > sc27xx_fgu_external_power_changed() dereferences data->battery, > which gets sets in ab8500_btemp_probe() like this: > > data->battery = devm_power_supply_register(dev, &sc27xx_fgu_desc, > &fgu_cfg); > > As soon as devm_power_supply_register() has called device_add() > the external_power_changed callback can get called. So there is a window > where sc27xx_fgu_external_power_changed() may get called while > data->battery has not been set yet leading to a NULL pointer dereference. > > Fixing this is easy. The external_power_changed callback gets passed > the power_supply which will eventually get stored in data->battery, > so sc27xx_fgu_external_power_changed() can simply directly use > the passed in psy argument which is always valid. > > After this change sc27xx_fgu_external_power_changed() is reduced to just > "power_supply_changed(psy);" and it has the same prototype. While at it > simply replace it with making the external_power_changed callback > directly point to power_supply_changed. > > Cc: Orson Zhai <orsonzhai@gmail.com> > Cc: Baolin Wang <baolin.wang@linux.alibaba.com> > Cc: Chunyan Zhang <zhang.lyra@gmail.com> > Signed-off-by: Hans de Goede <hdegoede@redhat.com> Looks good to me. Thanks. Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com> > --- > Note this has been compile tested only > --- > drivers/power/supply/sc27xx_fuel_gauge.c | 9 +-------- > 1 file changed, 1 insertion(+), 8 deletions(-) > > diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c > index 632977f84b95..bd23c4d9fed4 100644 > --- a/drivers/power/supply/sc27xx_fuel_gauge.c > +++ b/drivers/power/supply/sc27xx_fuel_gauge.c > @@ -733,13 +733,6 @@ static int sc27xx_fgu_set_property(struct power_supply *psy, > return ret; > } > > -static void sc27xx_fgu_external_power_changed(struct power_supply *psy) > -{ > - struct sc27xx_fgu_data *data = power_supply_get_drvdata(psy); > - > - power_supply_changed(data->battery); > -} > - > static int sc27xx_fgu_property_is_writeable(struct power_supply *psy, > enum power_supply_property psp) > { > @@ -774,7 +767,7 @@ static const struct power_supply_desc sc27xx_fgu_desc = { > .num_properties = ARRAY_SIZE(sc27xx_fgu_props), > .get_property = sc27xx_fgu_get_property, > .set_property = sc27xx_fgu_set_property, > - .external_power_changed = sc27xx_fgu_external_power_changed, > + .external_power_changed = power_supply_changed, > .property_is_writeable = sc27xx_fgu_property_is_writeable, > .no_thermal = true, > };
diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 632977f84b95..bd23c4d9fed4 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -733,13 +733,6 @@ static int sc27xx_fgu_set_property(struct power_supply *psy, return ret; } -static void sc27xx_fgu_external_power_changed(struct power_supply *psy) -{ - struct sc27xx_fgu_data *data = power_supply_get_drvdata(psy); - - power_supply_changed(data->battery); -} - static int sc27xx_fgu_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { @@ -774,7 +767,7 @@ static const struct power_supply_desc sc27xx_fgu_desc = { .num_properties = ARRAY_SIZE(sc27xx_fgu_props), .get_property = sc27xx_fgu_get_property, .set_property = sc27xx_fgu_set_property, - .external_power_changed = sc27xx_fgu_external_power_changed, + .external_power_changed = power_supply_changed, .property_is_writeable = sc27xx_fgu_property_is_writeable, .no_thermal = true, };
sc27xx_fgu_external_power_changed() dereferences data->battery, which gets sets in ab8500_btemp_probe() like this: data->battery = devm_power_supply_register(dev, &sc27xx_fgu_desc, &fgu_cfg); As soon as devm_power_supply_register() has called device_add() the external_power_changed callback can get called. So there is a window where sc27xx_fgu_external_power_changed() may get called while data->battery has not been set yet leading to a NULL pointer dereference. Fixing this is easy. The external_power_changed callback gets passed the power_supply which will eventually get stored in data->battery, so sc27xx_fgu_external_power_changed() can simply directly use the passed in psy argument which is always valid. After this change sc27xx_fgu_external_power_changed() is reduced to just "power_supply_changed(psy);" and it has the same prototype. While at it simply replace it with making the external_power_changed callback directly point to power_supply_changed. Cc: Orson Zhai <orsonzhai@gmail.com> Cc: Baolin Wang <baolin.wang@linux.alibaba.com> Cc: Chunyan Zhang <zhang.lyra@gmail.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- Note this has been compile tested only --- drivers/power/supply/sc27xx_fuel_gauge.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-)