public inbox for linux-pm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed()
@ 2025-12-20 22:46 Waqar Hameed
  2025-12-20 22:46 ` [PATCH 2/3] power: supply: wm97xx: Use devm_power_supply_register() Waqar Hameed
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Waqar Hameed @ 2025-12-20 22:46 UTC (permalink / raw)
  To: Sebastian Reichel, Anton Vorontsov, Marek Vasut
  Cc: kernel, linux-pm, linux-kernel

The majority of the drivers in `drivers/power/supply/` do the right
thing when registering an interrupt handler and the `power_supply`
handle; namely making sure that the interrupt handler only runs while
the `power_supply` handle is valid. This driver requests the IRQ a
little too soon, and this can lead to a nasty NULL pointer dereference
as thoroughly explained in the commit message. This patch series also
contains some other related clean-ups that makes life a little easier.

This issue was found when writing a new driver for the upcoming TI
BQ25630 [1]. Patch adding support for that one will be sent as soon as
TI releases the datasheet publicly, which should be anytime soon...

[1] https://www.ti.com/product/BQ25630

Waqar Hameed (3):
  power: supply: wm97xx: Fix NULL pointer dereference in
    power_supply_changed()
  power: supply: wm97xx: Use devm_power_supply_register()
  power: supply: wm97xx: Use devm_kcalloc()

 drivers/power/supply/wm97xx_battery.c | 40 ++++++++++-----------------
 1 file changed, 15 insertions(+), 25 deletions(-)


base-commit: fa084c35afa13ab07a860ef0936cd987f9aa0460
-- 
2.39.5


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 2/3] power: supply: wm97xx: Use devm_power_supply_register()
  2025-12-20 22:46 [PATCH 0/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed() Waqar Hameed
@ 2025-12-20 22:46 ` Waqar Hameed
  2026-01-12  1:36   ` Sebastian Reichel
  2025-12-20 22:46 ` [PATCH 1/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed() Waqar Hameed
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: Waqar Hameed @ 2025-12-20 22:46 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: kernel, linux-pm, linux-kernel

Instead of handling the registration manually, use the automatic
`devres` variant `devm_power_supply_register()`. This is less error
prone and cleaner.

Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
---
 drivers/power/supply/wm97xx_battery.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c
index f00722c88c6fe..e91467dcab19c 100644
--- a/drivers/power/supply/wm97xx_battery.c
+++ b/drivers/power/supply/wm97xx_battery.c
@@ -223,7 +223,7 @@ static int wm97xx_bat_probe(struct platform_device *dev)
 	bat_psy_desc.properties = prop;
 	bat_psy_desc.num_properties = props;
 
-	bat_psy = power_supply_register(&dev->dev, &bat_psy_desc, &cfg);
+	bat_psy = devm_power_supply_register(&dev->dev, &bat_psy_desc, &cfg);
 	if (!IS_ERR(bat_psy)) {
 		schedule_work(&bat_work);
 	} else {
@@ -237,15 +237,12 @@ static int wm97xx_bat_probe(struct platform_device *dev)
 		if (ret) {
 			dev_err_probe(&dev->dev, ret,
 				      "failed to request GPIO irq\n");
-			goto unregister;
+			goto free;
 		}
 	}
 
 	return 0;
 
-unregister:
-	power_supply_unregister(bat_psy);
-
 free:
 	kfree(prop);
 
@@ -257,7 +254,6 @@ static void wm97xx_bat_remove(struct platform_device *dev)
 	if (charge_gpiod)
 		free_irq(gpiod_to_irq(charge_gpiod), dev);
 	cancel_work_sync(&bat_work);
-	power_supply_unregister(bat_psy);
 	kfree(prop);
 }
 
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 1/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed()
  2025-12-20 22:46 [PATCH 0/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed() Waqar Hameed
  2025-12-20 22:46 ` [PATCH 2/3] power: supply: wm97xx: Use devm_power_supply_register() Waqar Hameed
@ 2025-12-20 22:46 ` Waqar Hameed
  2025-12-20 22:46 ` [PATCH 3/3] power: supply: wm97xx: Use devm_kcalloc() Waqar Hameed
  2026-01-12  1:56 ` (subset) [PATCH 0/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed() Sebastian Reichel
  3 siblings, 0 replies; 7+ messages in thread
From: Waqar Hameed @ 2025-12-20 22:46 UTC (permalink / raw)
  To: Sebastian Reichel, Anton Vorontsov, Marek Vasut
  Cc: kernel, linux-pm, linux-kernel

In `probe()`, `request_irq()` is called before allocating/registering a
`power_supply` handle. If an interrupt is fired between the call to
`request_irq()` and `power_supply_register()`, the `power_supply` handle
will be used uninitialized in `power_supply_changed()` in
`wm97xx_bat_update()` (triggered from the interrupt handler). This will
lead to a `NULL` pointer dereference since

Fix this racy `NULL` pointer dereference by making sure the IRQ is
requested _after_ the registration of the `power_supply` handle. Since
the IRQ is the last thing requests in the `probe()` now, remove the
error path for freeing it. Instead add one for unregistering the
`power_supply` handle when IRQ request fails.

Fixes: 7c87942aef52 ("wm97xx_battery: Use irq to detect charger state")
Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
---
 drivers/power/supply/wm97xx_battery.c | 34 +++++++++++++++------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c
index b3b0c37a9dd2d..f00722c88c6fe 100644
--- a/drivers/power/supply/wm97xx_battery.c
+++ b/drivers/power/supply/wm97xx_battery.c
@@ -178,12 +178,6 @@ static int wm97xx_bat_probe(struct platform_device *dev)
 				     "failed to get charge GPIO\n");
 	if (charge_gpiod) {
 		gpiod_set_consumer_name(charge_gpiod, "BATT CHRG");
-		ret = request_irq(gpiod_to_irq(charge_gpiod),
-				wm97xx_chrg_irq, 0,
-				"AC Detect", dev);
-		if (ret)
-			return dev_err_probe(&dev->dev, ret,
-					     "failed to request GPIO irq\n");
 		props++;	/* POWER_SUPPLY_PROP_STATUS */
 	}
 
@@ -199,10 +193,8 @@ static int wm97xx_bat_probe(struct platform_device *dev)
 		props++;	/* POWER_SUPPLY_PROP_VOLTAGE_MIN */
 
 	prop = kcalloc(props, sizeof(*prop), GFP_KERNEL);
-	if (!prop) {
-		ret = -ENOMEM;
-		goto err3;
-	}
+	if (!prop)
+		return -ENOMEM;
 
 	prop[i++] = POWER_SUPPLY_PROP_PRESENT;
 	if (charge_gpiod)
@@ -236,15 +228,27 @@ static int wm97xx_bat_probe(struct platform_device *dev)
 		schedule_work(&bat_work);
 	} else {
 		ret = PTR_ERR(bat_psy);
-		goto err4;
+		goto free;
+	}
+
+	if (charge_gpiod) {
+		ret = request_irq(gpiod_to_irq(charge_gpiod), wm97xx_chrg_irq,
+				  0, "AC Detect", dev);
+		if (ret) {
+			dev_err_probe(&dev->dev, ret,
+				      "failed to request GPIO irq\n");
+			goto unregister;
+		}
 	}
 
 	return 0;
-err4:
+
+unregister:
+	power_supply_unregister(bat_psy);
+
+free:
 	kfree(prop);
-err3:
-	if (charge_gpiod)
-		free_irq(gpiod_to_irq(charge_gpiod), dev);
+
 	return ret;
 }
 
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/3] power: supply: wm97xx: Use devm_kcalloc()
  2025-12-20 22:46 [PATCH 0/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed() Waqar Hameed
  2025-12-20 22:46 ` [PATCH 2/3] power: supply: wm97xx: Use devm_power_supply_register() Waqar Hameed
  2025-12-20 22:46 ` [PATCH 1/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed() Waqar Hameed
@ 2025-12-20 22:46 ` Waqar Hameed
  2026-01-12  1:56 ` (subset) [PATCH 0/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed() Sebastian Reichel
  3 siblings, 0 replies; 7+ messages in thread
From: Waqar Hameed @ 2025-12-20 22:46 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: kernel, linux-pm, linux-kernel

Instead of handling the memory allocation manually, use the automatic
`devres` variant `devm_kcalloc()`. This is less error prone and
eliminates the `goto`-path.

Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
---
 drivers/power/supply/wm97xx_battery.c | 26 ++++++++------------------
 1 file changed, 8 insertions(+), 18 deletions(-)

diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c
index e91467dcab19c..a6c55b1e02863 100644
--- a/drivers/power/supply/wm97xx_battery.c
+++ b/drivers/power/supply/wm97xx_battery.c
@@ -192,7 +192,7 @@ static int wm97xx_bat_probe(struct platform_device *dev)
 	if (pdata->min_voltage >= 0)
 		props++;	/* POWER_SUPPLY_PROP_VOLTAGE_MIN */
 
-	prop = kcalloc(props, sizeof(*prop), GFP_KERNEL);
+	prop = devm_kcalloc(&dev->dev, props, sizeof(*prop), GFP_KERNEL);
 	if (!prop)
 		return -ENOMEM;
 
@@ -224,29 +224,20 @@ static int wm97xx_bat_probe(struct platform_device *dev)
 	bat_psy_desc.num_properties = props;
 
 	bat_psy = devm_power_supply_register(&dev->dev, &bat_psy_desc, &cfg);
-	if (!IS_ERR(bat_psy)) {
-		schedule_work(&bat_work);
-	} else {
-		ret = PTR_ERR(bat_psy);
-		goto free;
-	}
+	if (IS_ERR(bat_psy))
+		return PTR_ERR(bat_psy);
+
+	schedule_work(&bat_work);
 
 	if (charge_gpiod) {
 		ret = request_irq(gpiod_to_irq(charge_gpiod), wm97xx_chrg_irq,
 				  0, "AC Detect", dev);
-		if (ret) {
-			dev_err_probe(&dev->dev, ret,
-				      "failed to request GPIO irq\n");
-			goto free;
-		}
+		if (ret)
+			return dev_err_probe(&dev->dev, ret,
+					     "failed to request GPIO irq\n");
 	}
 
 	return 0;
-
-free:
-	kfree(prop);
-
-	return ret;
 }
 
 static void wm97xx_bat_remove(struct platform_device *dev)
@@ -254,7 +245,6 @@ static void wm97xx_bat_remove(struct platform_device *dev)
 	if (charge_gpiod)
 		free_irq(gpiod_to_irq(charge_gpiod), dev);
 	cancel_work_sync(&bat_work);
-	kfree(prop);
 }
 
 static struct platform_driver wm97xx_bat_driver = {
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/3] power: supply: wm97xx: Use devm_power_supply_register()
  2025-12-20 22:46 ` [PATCH 2/3] power: supply: wm97xx: Use devm_power_supply_register() Waqar Hameed
@ 2026-01-12  1:36   ` Sebastian Reichel
  2026-01-14 10:51     ` Waqar Hameed
  0 siblings, 1 reply; 7+ messages in thread
From: Sebastian Reichel @ 2026-01-12  1:36 UTC (permalink / raw)
  To: Waqar Hameed; +Cc: kernel, linux-pm, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1789 bytes --]

Hi,

On Sat, Dec 20, 2025 at 11:46:24PM +0100, Waqar Hameed wrote:
> Instead of handling the registration manually, use the automatic
> `devres` variant `devm_power_supply_register()`. This is less error
> prone and cleaner.
> 
> Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
> ---
>  drivers/power/supply/wm97xx_battery.c | 8 ++------
>  1 file changed, 2 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c
> index f00722c88c6fe..e91467dcab19c 100644
> --- a/drivers/power/supply/wm97xx_battery.c
> +++ b/drivers/power/supply/wm97xx_battery.c
> @@ -223,7 +223,7 @@ static int wm97xx_bat_probe(struct platform_device *dev)
>  	bat_psy_desc.properties = prop;
>  	bat_psy_desc.num_properties = props;
>  
> -	bat_psy = power_supply_register(&dev->dev, &bat_psy_desc, &cfg);
> +	bat_psy = devm_power_supply_register(&dev->dev, &bat_psy_desc, &cfg);
>  	if (!IS_ERR(bat_psy)) {
>  		schedule_work(&bat_work);
>  	} else {
> @@ -237,15 +237,12 @@ static int wm97xx_bat_probe(struct platform_device *dev)
>  		if (ret) {
>  			dev_err_probe(&dev->dev, ret,
>  				      "failed to request GPIO irq\n");
> -			goto unregister;
> +			goto free;
>  		}
>  	}
>  
>  	return 0;
>  
> -unregister:
> -	power_supply_unregister(bat_psy);
> -
>  free:
>  	kfree(prop);
>  
> @@ -257,7 +254,6 @@ static void wm97xx_bat_remove(struct platform_device *dev)
>  	if (charge_gpiod)
>  		free_irq(gpiod_to_irq(charge_gpiod), dev);
>  	cancel_work_sync(&bat_work);
> -	power_supply_unregister(bat_psy);
>  	kfree(prop);
>  }

This free's prop before bat_psy. You fix that in the next patch, but
to be bisectable those two patches must be swapped.

Greetings,

-- Sebastian

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: (subset) [PATCH 0/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed()
  2025-12-20 22:46 [PATCH 0/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed() Waqar Hameed
                   ` (2 preceding siblings ...)
  2025-12-20 22:46 ` [PATCH 3/3] power: supply: wm97xx: Use devm_kcalloc() Waqar Hameed
@ 2026-01-12  1:56 ` Sebastian Reichel
  3 siblings, 0 replies; 7+ messages in thread
From: Sebastian Reichel @ 2026-01-12  1:56 UTC (permalink / raw)
  To: Sebastian Reichel, Anton Vorontsov, Marek Vasut, Waqar Hameed
  Cc: kernel, linux-pm, linux-kernel


On Sat, 20 Dec 2025 23:46:24 +0100, Waqar Hameed wrote:
> The majority of the drivers in `drivers/power/supply/` do the right
> thing when registering an interrupt handler and the `power_supply`
> handle; namely making sure that the interrupt handler only runs while
> the `power_supply` handle is valid. This driver requests the IRQ a
> little too soon, and this can lead to a nasty NULL pointer dereference
> as thoroughly explained in the commit message. This patch series also
> contains some other related clean-ups that makes life a little easier.
> 
> [...]

Applied, thanks!

[1/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed()
      commit: 39fe0eac6d755ef215026518985fcf8de9360e9e

Best regards,
-- 
Sebastian Reichel <sebastian.reichel@collabora.com>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/3] power: supply: wm97xx: Use devm_power_supply_register()
  2026-01-12  1:36   ` Sebastian Reichel
@ 2026-01-14 10:51     ` Waqar Hameed
  0 siblings, 0 replies; 7+ messages in thread
From: Waqar Hameed @ 2026-01-14 10:51 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: kernel, linux-pm, linux-kernel

On Mon, Jan 12, 2026 at 02:36 +0100 Sebastian Reichel <sebastian.reichel@collabora.com> wrote:

[...]

>> @@ -257,7 +254,6 @@ static void wm97xx_bat_remove(struct platform_device *dev)
>>  	if (charge_gpiod)
>>  		free_irq(gpiod_to_irq(charge_gpiod), dev);
>>  	cancel_work_sync(&bat_work);
>> -	power_supply_unregister(bat_psy);
>>  	kfree(prop);
>>  }
>
> This free's prop before bat_psy. You fix that in the next patch, but
> to be bisectable those two patches must be swapped.

Ah, of course! Let's swap the patches in v2.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-01-14 10:51 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-20 22:46 [PATCH 0/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed() Waqar Hameed
2025-12-20 22:46 ` [PATCH 2/3] power: supply: wm97xx: Use devm_power_supply_register() Waqar Hameed
2026-01-12  1:36   ` Sebastian Reichel
2026-01-14 10:51     ` Waqar Hameed
2025-12-20 22:46 ` [PATCH 1/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed() Waqar Hameed
2025-12-20 22:46 ` [PATCH 3/3] power: supply: wm97xx: Use devm_kcalloc() Waqar Hameed
2026-01-12  1:56 ` (subset) [PATCH 0/3] power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed() Sebastian Reichel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox