mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-03 23:58:05 +00:00
thermal: of: fix double-free on unregistration
commitac4436a5b2
upstream. Since commit3d439b1a2a
("thermal/core: Alloc-copy-free the thermal zone parameters structure"), thermal_zone_device_register() allocates a copy of the tzp argument and frees it when unregistering, so thermal_of_zone_register() now ends up leaking its original tzp and double-freeing the tzp copy. Fix this by locating tzp on stack instead. Fixes:3d439b1a2a
("thermal/core: Alloc-copy-free the thermal zone parameters structure") Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de> Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org> Cc: 6.4+ <stable@vger.kernel.org> # 6.4+: 8bcbb18c61d6: thermal: core: constify params in thermal_zone_device_register Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
5dac557301
commit
adce490894
1 changed files with 6 additions and 21 deletions
|
@ -238,17 +238,13 @@ static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdel
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct thermal_zone_params *thermal_of_parameters_init(struct device_node *np)
|
static void thermal_of_parameters_init(struct device_node *np,
|
||||||
|
struct thermal_zone_params *tzp)
|
||||||
{
|
{
|
||||||
struct thermal_zone_params *tzp;
|
|
||||||
int coef[2];
|
int coef[2];
|
||||||
int ncoef = ARRAY_SIZE(coef);
|
int ncoef = ARRAY_SIZE(coef);
|
||||||
int prop, ret;
|
int prop, ret;
|
||||||
|
|
||||||
tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
|
|
||||||
if (!tzp)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
tzp->no_hwmon = true;
|
tzp->no_hwmon = true;
|
||||||
|
|
||||||
if (!of_property_read_u32(np, "sustainable-power", &prop))
|
if (!of_property_read_u32(np, "sustainable-power", &prop))
|
||||||
|
@ -267,8 +263,6 @@ static struct thermal_zone_params *thermal_of_parameters_init(struct device_node
|
||||||
|
|
||||||
tzp->slope = coef[0];
|
tzp->slope = coef[0];
|
||||||
tzp->offset = coef[1];
|
tzp->offset = coef[1];
|
||||||
|
|
||||||
return tzp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct device_node *thermal_of_zone_get_by_name(struct thermal_zone_device *tz)
|
static struct device_node *thermal_of_zone_get_by_name(struct thermal_zone_device *tz)
|
||||||
|
@ -442,13 +436,11 @@ static int thermal_of_unbind(struct thermal_zone_device *tz,
|
||||||
static void thermal_of_zone_unregister(struct thermal_zone_device *tz)
|
static void thermal_of_zone_unregister(struct thermal_zone_device *tz)
|
||||||
{
|
{
|
||||||
struct thermal_trip *trips = tz->trips;
|
struct thermal_trip *trips = tz->trips;
|
||||||
struct thermal_zone_params *tzp = tz->tzp;
|
|
||||||
struct thermal_zone_device_ops *ops = tz->ops;
|
struct thermal_zone_device_ops *ops = tz->ops;
|
||||||
|
|
||||||
thermal_zone_device_disable(tz);
|
thermal_zone_device_disable(tz);
|
||||||
thermal_zone_device_unregister(tz);
|
thermal_zone_device_unregister(tz);
|
||||||
kfree(trips);
|
kfree(trips);
|
||||||
kfree(tzp);
|
|
||||||
kfree(ops);
|
kfree(ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,7 +469,7 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
|
||||||
{
|
{
|
||||||
struct thermal_zone_device *tz;
|
struct thermal_zone_device *tz;
|
||||||
struct thermal_trip *trips;
|
struct thermal_trip *trips;
|
||||||
struct thermal_zone_params *tzp;
|
struct thermal_zone_params tzp = {};
|
||||||
struct thermal_zone_device_ops *of_ops;
|
struct thermal_zone_device_ops *of_ops;
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
int delay, pdelay;
|
int delay, pdelay;
|
||||||
|
@ -509,12 +501,7 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
|
||||||
goto out_kfree_trips;
|
goto out_kfree_trips;
|
||||||
}
|
}
|
||||||
|
|
||||||
tzp = thermal_of_parameters_init(np);
|
thermal_of_parameters_init(np, &tzp);
|
||||||
if (IS_ERR(tzp)) {
|
|
||||||
ret = PTR_ERR(tzp);
|
|
||||||
pr_err("Failed to initialize parameter from %pOFn: %d\n", np, ret);
|
|
||||||
goto out_kfree_trips;
|
|
||||||
}
|
|
||||||
|
|
||||||
of_ops->bind = thermal_of_bind;
|
of_ops->bind = thermal_of_bind;
|
||||||
of_ops->unbind = thermal_of_unbind;
|
of_ops->unbind = thermal_of_unbind;
|
||||||
|
@ -522,12 +509,12 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
|
||||||
mask = GENMASK_ULL((ntrips) - 1, 0);
|
mask = GENMASK_ULL((ntrips) - 1, 0);
|
||||||
|
|
||||||
tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips,
|
tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips,
|
||||||
mask, data, of_ops, tzp,
|
mask, data, of_ops, &tzp,
|
||||||
pdelay, delay);
|
pdelay, delay);
|
||||||
if (IS_ERR(tz)) {
|
if (IS_ERR(tz)) {
|
||||||
ret = PTR_ERR(tz);
|
ret = PTR_ERR(tz);
|
||||||
pr_err("Failed to register thermal zone %pOFn: %d\n", np, ret);
|
pr_err("Failed to register thermal zone %pOFn: %d\n", np, ret);
|
||||||
goto out_kfree_tzp;
|
goto out_kfree_trips;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = thermal_zone_device_enable(tz);
|
ret = thermal_zone_device_enable(tz);
|
||||||
|
@ -540,8 +527,6 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
|
||||||
|
|
||||||
return tz;
|
return tz;
|
||||||
|
|
||||||
out_kfree_tzp:
|
|
||||||
kfree(tzp);
|
|
||||||
out_kfree_trips:
|
out_kfree_trips:
|
||||||
kfree(trips);
|
kfree(trips);
|
||||||
out_kfree_of_ops:
|
out_kfree_of_ops:
|
||||||
|
|
Loading…
Reference in a new issue