diff mbox series

[2/2] thermal: of: fix double-free on unregistration

Message ID 20230708112720.2897484-2-a.fatoum@pengutronix.de (mailing list archive)
State Mainlined, archived
Headers show
Series [1/2] thermal: core: constify params in thermal_zone_device_register | expand

Commit Message

Ahmad Fatoum July 8, 2023, 11:27 a.m. UTC
Since commit 3d439b1a2ad3 ("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: 3d439b1a2ad3 ("thermal/core: Alloc-copy-free the thermal zone parameters structure")
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 drivers/thermal/thermal_of.c | 27 ++++++---------------------
 1 file changed, 6 insertions(+), 21 deletions(-)

Comments

Rafael J. Wysocki July 11, 2023, 6:05 p.m. UTC | #1
On Sat, Jul 8, 2023 at 1:27 PM Ahmad Fatoum <a.fatoum@pengutronix.de> wrote:
>
> Since commit 3d439b1a2ad3 ("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: 3d439b1a2ad3 ("thermal/core: Alloc-copy-free the thermal zone parameters structure")
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>

Daniel, this looks like a genuine fix to me, so I'm inclined to pick
it up directly.

Any objections?

> ---
>  drivers/thermal/thermal_of.c | 27 ++++++---------------------
>  1 file changed, 6 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
> index 6fb14e521197..bc07ae1c284c 100644
> --- a/drivers/thermal/thermal_of.c
> +++ b/drivers/thermal/thermal_of.c
> @@ -238,17 +238,13 @@ static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdel
>         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 ncoef = ARRAY_SIZE(coef);
>         int prop, ret;
>
> -       tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
> -       if (!tzp)
> -               return ERR_PTR(-ENOMEM);
> -
>         tzp->no_hwmon = true;
>
>         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->offset = coef[1];
> -
> -       return tzp;
>  }
>
>  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)
>  {
>         struct thermal_trip *trips = tz->trips;
> -       struct thermal_zone_params *tzp = tz->tzp;
>         struct thermal_zone_device_ops *ops = tz->ops;
>
>         thermal_zone_device_disable(tz);
>         thermal_zone_device_unregister(tz);
>         kfree(trips);
> -       kfree(tzp);
>         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_trip *trips;
> -       struct thermal_zone_params *tzp;
> +       struct thermal_zone_params tzp = {};
>         struct thermal_zone_device_ops *of_ops;
>         struct device_node *np;
>         int delay, pdelay;
> @@ -509,12 +501,7 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
>                 goto out_kfree_trips;
>         }
>
> -       tzp = thermal_of_parameters_init(np);
> -       if (IS_ERR(tzp)) {
> -               ret = PTR_ERR(tzp);
> -               pr_err("Failed to initialize parameter from %pOFn: %d\n", np, ret);
> -               goto out_kfree_trips;
> -       }
> +       thermal_of_parameters_init(np, &tzp);
>
>         of_ops->bind = thermal_of_bind;
>         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);
>
>         tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips,
> -                                                    mask, data, of_ops, tzp,
> +                                                    mask, data, of_ops, &tzp,
>                                                      pdelay, delay);
>         if (IS_ERR(tz)) {
>                 ret = PTR_ERR(tz);
>                 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);
> @@ -540,8 +527,6 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
>
>         return tz;
>
> -out_kfree_tzp:
> -       kfree(tzp);
>  out_kfree_trips:
>         kfree(trips);
>  out_kfree_of_ops:
> --
Daniel Lezcano July 13, 2023, 12:52 p.m. UTC | #2
On 11/07/2023 20:05, Rafael J. Wysocki wrote:
> On Sat, Jul 8, 2023 at 1:27 PM Ahmad Fatoum <a.fatoum@pengutronix.de> wrote:
>>
>> Since commit 3d439b1a2ad3 ("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: 3d439b1a2ad3 ("thermal/core: Alloc-copy-free the thermal zone parameters structure")
>> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> 
> Daniel, this looks like a genuine fix to me, so I'm inclined to pick
> it up directly.
> 
> Any objections?
> 

No objection

Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
diff mbox series

Patch

diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index 6fb14e521197..bc07ae1c284c 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -238,17 +238,13 @@  static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdel
 	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 ncoef = ARRAY_SIZE(coef);
 	int prop, ret;
 
-	tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
-	if (!tzp)
-		return ERR_PTR(-ENOMEM);
-
 	tzp->no_hwmon = true;
 
 	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->offset = coef[1];
-
-	return tzp;
 }
 
 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)
 {
 	struct thermal_trip *trips = tz->trips;
-	struct thermal_zone_params *tzp = tz->tzp;
 	struct thermal_zone_device_ops *ops = tz->ops;
 
 	thermal_zone_device_disable(tz);
 	thermal_zone_device_unregister(tz);
 	kfree(trips);
-	kfree(tzp);
 	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_trip *trips;
-	struct thermal_zone_params *tzp;
+	struct thermal_zone_params tzp = {};
 	struct thermal_zone_device_ops *of_ops;
 	struct device_node *np;
 	int delay, pdelay;
@@ -509,12 +501,7 @@  static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
 		goto out_kfree_trips;
 	}
 
-	tzp = thermal_of_parameters_init(np);
-	if (IS_ERR(tzp)) {
-		ret = PTR_ERR(tzp);
-		pr_err("Failed to initialize parameter from %pOFn: %d\n", np, ret);
-		goto out_kfree_trips;
-	}
+	thermal_of_parameters_init(np, &tzp);
 
 	of_ops->bind = thermal_of_bind;
 	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);
 
 	tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips,
-						     mask, data, of_ops, tzp,
+						     mask, data, of_ops, &tzp,
 						     pdelay, delay);
 	if (IS_ERR(tz)) {
 		ret = PTR_ERR(tz);
 		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);
@@ -540,8 +527,6 @@  static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
 
 	return tz;
 
-out_kfree_tzp:
-	kfree(tzp);
 out_kfree_trips:
 	kfree(trips);
 out_kfree_of_ops: