The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH] power: supply: ds2760_battery: fix NULL pointer dereference in w1_ds2760_remove_slave()
@ 2026-08-08 21:44 Ivy Lopez
  2026-08-12 22:00 ` Sebastian Reichel
  2026-08-13  0:41 ` [PATCH v2] power: supply: ds2760_battery: convert to devm-managed workqueue and pm_notifier Ivy Lopez
  0 siblings, 2 replies; 5+ messages in thread
From: Ivy Lopez @ 2026-08-08 21:44 UTC (permalink / raw)
  To: sre; +Cc: linux-pm, linux-kernel, Ivy Lopez

w1_ds2760_add_slave()'s failure paths (di_alloc_failed, batt_failed,
workqueue_failed) are all empty labels that just return the error
code, with no explicit unwind. This works for di itself and the
registered power supply, both are devm-managed against the w1 slave
device and get cleaned up automatically. But di->monitor_wqueue and
di->pm_notifier are not devm-managed, and are only ever set up in
the success tail of the function, after the workqueue allocation and
power supply registration have both succeeded.

The w1 core's BUS_NOTIFY_ADD_DEVICE handling in w1_family_notify()
logs and returns on a failing add_slave(), but does not prevent the
w1 slave device from later being removed from the bus, which
triggers BUS_NOTIFY_DEL_DEVICE and an unconditional call to
remove_slave(). This means w1_ds2760_remove_slave() is effectively
the only failure-unwind path for a partially initialized di, and
needs to treat every field as potentially never having been set.

Currently it does not: it unconditionally calls
destroy_workqueue(di->monitor_wqueue), which crashes with a NULL
pointer dereference if add_slave() failed before or during the
workqueue allocation (e.g. on a power_supply_register() failure, as
seen when a colliding sysfs name from a misdetected slave device
causes registration to fail).

sl->family_data can also be NULL if add_slave() failed at its own
allocation, before family_data was ever set, which would crash on
the very first dereference in remove_slave().

Fix both: return early if di is NULL, and only call
destroy_workqueue() if monitor_wqueue was actually allocated.
unregister_pm_notifier() and cancel_delayed_work_sync() are safe to
call unconditionally: the former is a no-op if the notifier was
never registered, and the latter operates on the embedded
delayed_work struct, which is always validly initialized by the
time remove_slave() can run with a non-NULL di.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=217832
Signed-off-by: Ivy Lopez <skunkolee@gmail.com>
---
 drivers/power/supply/ds2760_battery.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/power/supply/ds2760_battery.c b/drivers/power/supply/ds2760_battery.c
index 142c7492c3c2..3c2433f6b5e9 100644
--- a/drivers/power/supply/ds2760_battery.c
+++ b/drivers/power/supply/ds2760_battery.c
@@ -723,9 +723,13 @@ static void w1_ds2760_remove_slave(struct w1_slave *sl)
 {
 	struct ds2760_device_info *di = sl->family_data;
 
+	if (!di)
+		return;
+
 	unregister_pm_notifier(&di->pm_notifier);
 	cancel_delayed_work_sync(&di->monitor_work);
-	destroy_workqueue(di->monitor_wqueue);
+	if (di->monitor_wqueue)
+		destroy_workqueue(di->monitor_wqueue);
 }
 
 #ifdef CONFIG_OF
-- 
2.55.0


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

* Re: [PATCH] power: supply: ds2760_battery: fix NULL pointer dereference in w1_ds2760_remove_slave()
  2026-08-08 21:44 [PATCH] power: supply: ds2760_battery: fix NULL pointer dereference in w1_ds2760_remove_slave() Ivy Lopez
@ 2026-08-12 22:00 ` Sebastian Reichel
  2026-08-13  0:41 ` [PATCH v2] power: supply: ds2760_battery: convert to devm-managed workqueue and pm_notifier Ivy Lopez
  1 sibling, 0 replies; 5+ messages in thread
From: Sebastian Reichel @ 2026-08-12 22:00 UTC (permalink / raw)
  To: Ivy Lopez; +Cc: linux-pm, linux-kernel

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

Hi,

On Sat, Aug 08, 2026 at 03:44:58PM -0600, Ivy Lopez wrote:
> w1_ds2760_add_slave()'s failure paths (di_alloc_failed, batt_failed,
> workqueue_failed) are all empty labels that just return the error
> code, with no explicit unwind. This works for di itself and the
> registered power supply, both are devm-managed against the w1 slave
> device and get cleaned up automatically. But di->monitor_wqueue and
> di->pm_notifier are not devm-managed, and are only ever set up in
> the success tail of the function, after the workqueue allocation and
> power supply registration have both succeeded.
> 
> The w1 core's BUS_NOTIFY_ADD_DEVICE handling in w1_family_notify()
> logs and returns on a failing add_slave(), but does not prevent the
> w1 slave device from later being removed from the bus, which
> triggers BUS_NOTIFY_DEL_DEVICE and an unconditional call to
> remove_slave(). This means w1_ds2760_remove_slave() is effectively
> the only failure-unwind path for a partially initialized di, and
> needs to treat every field as potentially never having been set.
> 
> Currently it does not: it unconditionally calls
> destroy_workqueue(di->monitor_wqueue), which crashes with a NULL
> pointer dereference if add_slave() failed before or during the
> workqueue allocation (e.g. on a power_supply_register() failure, as
> seen when a colliding sysfs name from a misdetected slave device
> causes registration to fail).
> 
> sl->family_data can also be NULL if add_slave() failed at its own
> allocation, before family_data was ever set, which would crash on
> the very first dereference in remove_slave().
> 
> Fix both: return early if di is NULL, and only call
> destroy_workqueue() if monitor_wqueue was actually allocated.
> unregister_pm_notifier() and cancel_delayed_work_sync() are safe to
> call unconditionally: the former is a no-op if the notifier was
> never registered, and the latter operates on the embedded
> delayed_work struct, which is always validly initialized by the
> time remove_slave() can run with a non-NULL di.
> 
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=217832
> Signed-off-by: Ivy Lopez <skunkolee@gmail.com>

This should get a Fixes tag.

> ---
>  drivers/power/supply/ds2760_battery.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/power/supply/ds2760_battery.c b/drivers/power/supply/ds2760_battery.c
> index 142c7492c3c2..3c2433f6b5e9 100644
> --- a/drivers/power/supply/ds2760_battery.c
> +++ b/drivers/power/supply/ds2760_battery.c
> @@ -723,9 +723,13 @@ static void w1_ds2760_remove_slave(struct w1_slave *sl)
>  {
>  	struct ds2760_device_info *di = sl->family_data;
>  
> +	if (!di)
> +		return;
> +
>  	unregister_pm_notifier(&di->pm_notifier);
>  	cancel_delayed_work_sync(&di->monitor_work);
> -	destroy_workqueue(di->monitor_wqueue);
> +	if (di->monitor_wqueue)
> +		destroy_workqueue(di->monitor_wqueue);

Considering the driver has mostly been converted to device managed
resources already, I think it makes sense to simply use
devm_alloc_ordered_workqueue() in the probe function and thus avoid
this problem. Also while at it switch INIT_DELAYED_WORK to
devm_delayed_work_autocancel() to get rid of
w1_ds2760_remove_slave(). Just make sure to do this *after*
allocating the workqueue.

Last but not least use devm_add_action_or_reset() for the
unregister_pm_notifier and simply drop the complete
w1_ds2760_remove_slave() function.

Greetings,

-- Sebastian

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

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

* [PATCH v2] power: supply: ds2760_battery: convert to devm-managed workqueue and pm_notifier
  2026-08-08 21:44 [PATCH] power: supply: ds2760_battery: fix NULL pointer dereference in w1_ds2760_remove_slave() Ivy Lopez
  2026-08-12 22:00 ` Sebastian Reichel
@ 2026-08-13  0:41 ` Ivy Lopez
  2026-08-13  0:41   ` [PATCH] w1: fix spelling mistakes in comments across the subsystem Ivy Lopez
  1 sibling, 1 reply; 5+ messages in thread
From: Ivy Lopez @ 2026-08-13  0:41 UTC (permalink / raw)
  To: sre; +Cc: linux-pm, linux-kernel, Ivy Lopez

Following review feedback, convert the driver to use devm-managed
resources instead of manual cleanup in w1_ds2760_remove_slave():

- devm_alloc_ordered_workqueue() for the monitor workqueue
- devm_delayed_work_autocancel() for the monitor delayed work
- devm_add_action_or_reset() to unregister the pm_notifier

This removes the need for w1_ds2760_remove_slave() entirely, along
with the NULL checks it required to safely handle a partially
initialized di on an add_slave() failure path.

Fixes: bf4973553737 ("power: supply: ds2760_battery: merge ds2760 supply driver with its w1 slave companion")
Suggested-by: Sebastian Reichel <sre@kernel.org>
Signed-off-by: Ivy Lopez <skunkolee@gmail.com>
---
 drivers/power/supply/ds2760_battery.c | 54 +++++++++++----------------
 1 file changed, 21 insertions(+), 33 deletions(-)

diff --git a/drivers/power/supply/ds2760_battery.c b/drivers/power/supply/ds2760_battery.c
index 3c2433f6b5e9..901aaaf916c4 100644
--- a/drivers/power/supply/ds2760_battery.c
+++ b/drivers/power/supply/ds2760_battery.c
@@ -23,6 +23,7 @@
 #include <linux/param.h>
 #include <linux/jiffies.h>
 #include <linux/workqueue.h>
+#include <linux/devm-helpers.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
@@ -621,6 +622,11 @@ static int ds2760_pm_notifier(struct notifier_block *notifier,
 	return NOTIFY_DONE;
 }
 
+static void ds2760_battery_unregister_pm_notifier(void *notifier)
+{
+	unregister_pm_notifier(notifier);
+}
+
 static int w1_ds2760_add_slave(struct w1_slave *sl)
 {
 	struct power_supply_config psy_cfg = {};
@@ -631,10 +637,8 @@ static int w1_ds2760_add_slave(struct w1_slave *sl)
 	char status;
 
 	di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
-	if (!di) {
-		retval = -ENOMEM;
-		goto di_alloc_failed;
-	}
+	if (!di)
+		return -ENOMEM;
 
 	snprintf(name, sizeof(name), "ds2760-battery.%d", dev->id);
 
@@ -695,41 +699,26 @@ static int w1_ds2760_add_slave(struct w1_slave *sl)
 	di->bat = devm_power_supply_register(dev, &di->bat_desc, &psy_cfg);
 	if (IS_ERR(di->bat)) {
 		dev_err(di->dev, "failed to register battery\n");
-		retval = PTR_ERR(di->bat);
-		goto batt_failed;
+		return PTR_ERR(di->bat);
 	}
 
-	INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work);
-	di->monitor_wqueue = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
-	if (!di->monitor_wqueue) {
-		retval = -ESRCH;
-		goto workqueue_failed;
-	}
+	di->monitor_wqueue = devm_alloc_ordered_workqueue(dev, name, WQ_MEM_RECLAIM);
+	if (!di->monitor_wqueue)
+		return -ESRCH;
+
+	retval = devm_delayed_work_autocancel(dev, &di->monitor_work,
+						 ds2760_battery_work);
+	if (retval)
+		return retval;
+
 	queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1);
 
 	di->pm_notifier.notifier_call = ds2760_pm_notifier;
 	register_pm_notifier(&di->pm_notifier);
 
-	goto success;
-
-workqueue_failed:
-batt_failed:
-di_alloc_failed:
-success:
-	return retval;
-}
-
-static void w1_ds2760_remove_slave(struct w1_slave *sl)
-{
-	struct ds2760_device_info *di = sl->family_data;
-
-	if (!di)
-		return;
-
-	unregister_pm_notifier(&di->pm_notifier);
-	cancel_delayed_work_sync(&di->monitor_work);
-	if (di->monitor_wqueue)
-		destroy_workqueue(di->monitor_wqueue);
+	return devm_add_action_or_reset(dev,
+					   ds2760_battery_unregister_pm_notifier,
+					   &di->pm_notifier);
 }
 
 #ifdef CONFIG_OF
@@ -741,7 +730,6 @@ static const struct of_device_id w1_ds2760_of_ids[] = {
 
 static const struct w1_family_ops w1_ds2760_fops = {
 	.add_slave	= w1_ds2760_add_slave,
-	.remove_slave	= w1_ds2760_remove_slave,
 	.groups		= w1_ds2760_groups,
 };
 
-- 
2.55.0


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

* [PATCH] w1: fix spelling mistakes in comments across the subsystem
  2026-08-13  0:41 ` [PATCH v2] power: supply: ds2760_battery: convert to devm-managed workqueue and pm_notifier Ivy Lopez
@ 2026-08-13  0:41   ` Ivy Lopez
  2026-08-13  0:43     ` Ivy Lopez
  0 siblings, 1 reply; 5+ messages in thread
From: Ivy Lopez @ 2026-08-13  0:41 UTC (permalink / raw)
  To: sre; +Cc: linux-pm, linux-kernel, Ivy Lopez

Following up on a prior patch that only fixed w1_netlink.c, sweep
the rest of the w1 subsystem for the same class of comment typos:
"loosing" -> "losing", "deatch" -> "detach", "messagse" -> "messages",
"continusly" -> "continuously", "attribut" -> "attribute",
"deactive" -> "deactivate", "determing" -> "determining",
"discrepency" -> "discrepancy", "rerurn" -> "return".

No functional change.

Signed-off-by: Ivy Lopez <skunkolee@gmail.com>
---
 drivers/w1/masters/ds2482.c    | 2 +-
 drivers/w1/masters/ds2490.c    | 4 ++--
 drivers/w1/masters/omap_hdq.c  | 2 +-
 drivers/w1/slaves/w1_ds28e17.c | 2 +-
 drivers/w1/slaves/w1_therm.c   | 2 +-
 drivers/w1/w1.c                | 2 +-
 drivers/w1/w1_family.c         | 2 +-
 drivers/w1/w1_netlink.h        | 2 +-
 8 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index 0069e6f854d7..040d66415a9b 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -421,7 +421,7 @@ static u8 ds2482_w1_set_pullup(void *data, int delay)
 
 	/* if delay is non-zero activate the pullup,
 	 * the strong pullup will be automatically deactivated
-	 * by the master, so do not explicitly deactive it
+	 * by the master, so do not explicitly deactivate it
 	 */
 	if (delay) {
 		/* both waits are crucial, otherwise devices might not be
diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c
index aa1f57f74397..3a0740d91a53 100644
--- a/drivers/w1/masters/ds2490.c
+++ b/drivers/w1/masters/ds2490.c
@@ -562,7 +562,7 @@ static int ds_write_bit(struct ds_device *dev, u8 bit)
 
 	/* Set COMM_ICP to write without a readback.  Note, this will
 	 * produce one time slot, a down followed by an up with COMM_D
-	 * only determing the timing.
+	 * only determining the timing.
 	 */
 	err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_ICP |
 		(bit ? COMM_D : 0), 0);
@@ -691,7 +691,7 @@ static void ds9490r_search(void *data, struct w1_master *master,
 	 * If the number of devices found is less than or equal to the
 	 * search_limit, that number of IDs will be returned.  If there are
 	 * more, search_limit IDs will be returned followed by a non-zero
-	 * discrepency value.
+	 * discrepancy value.
 	 */
 	struct ds_device *dev = data;
 	int err;
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index d13db3396570..0982efa2b25b 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -282,7 +282,7 @@ static int omap_hdq_break(struct hdq_data *hdq_data)
 	}
 
 	/*
-	 * wait for both INIT and GO bits rerurn to zero.
+	 * wait for both INIT and GO bits return to zero.
 	 * zero wait time expected for interrupt mode.
 	 */
 	ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
diff --git a/drivers/w1/slaves/w1_ds28e17.c b/drivers/w1/slaves/w1_ds28e17.c
index e53bc41bde3c..d656233afe54 100644
--- a/drivers/w1/slaves/w1_ds28e17.c
+++ b/drivers/w1/slaves/w1_ds28e17.c
@@ -101,7 +101,7 @@ static int w1_f19_i2c_busy_wait(struct w1_slave *sl, size_t count)
 		timebases[data->speed] * (data->stretch) * count
 		+ W1_F19_BUSY_GRATUITY);
 
-	/* Now continusly check the busy flag sent by the DS28E17. */
+	/* Now continuously check the busy flag sent by the DS28E17. */
 	checks = W1_F19_BUSY_CHECKS;
 	while ((checks--) > 0) {
 		/* Return success if the busy flag is cleared. */
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index d96b224e2215..02acf84ffec5 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -355,7 +355,7 @@ static DEVICE_ATTR_RW(alarms);
 static DEVICE_ATTR_RW(conv_time);
 static DEVICE_ATTR_RW(features);
 
-static DEVICE_ATTR_RW(therm_bulk_read); /* attribut at master level */
+static DEVICE_ATTR_RW(therm_bulk_read); /* attribute at master level */
 
 /* Interface Functions declaration */
 
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 486f321eadc8..67ea14a06319 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -1177,7 +1177,7 @@ int w1_process(void *data)
 
 		__set_current_state(TASK_INTERRUPTIBLE);
 
-		/* hold list_mutex until after interruptible to prevent loosing
+		/* hold list_mutex until after interruptible to prevent losing
 		 * the wakeup signal when async_cmd is added.
 		 */
 		mutex_unlock(&dev->list_mutex);
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c
index 97da4f156e9a..8152a43c8c76 100644
--- a/drivers/w1/w1_family.c
+++ b/drivers/w1/w1_family.c
@@ -67,7 +67,7 @@ void w1_unregister_family(struct w1_family *fent)
 	}
 	spin_unlock(&w1_flock);
 
-	/* deatch devices using this family code */
+	/* detach devices using this family code */
 	w1_reconnect_slaves(fent, 0);
 
 	while (atomic_read(&fent->refcnt)) {
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h
index 449680a61569..1818a06740eb 100644
--- a/drivers/w1/w1_netlink.h
+++ b/drivers/w1/w1_netlink.h
@@ -14,7 +14,7 @@
 /**
  * enum w1_cn_msg_flags - bitfield flags for struct cn_msg.flags
  *
- * @W1_CN_BUNDLE: Request bundling replies into fewer messagse.  Be prepared
+ * @W1_CN_BUNDLE: Request bundling replies into fewer messages.  Be prepared
  * to handle multiple struct cn_msg, struct w1_netlink_msg, and
  * struct w1_netlink_cmd in one packet.
  */
-- 
2.55.0


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

* Re: [PATCH] w1: fix spelling mistakes in comments across the subsystem
  2026-08-13  0:41   ` [PATCH] w1: fix spelling mistakes in comments across the subsystem Ivy Lopez
@ 2026-08-13  0:43     ` Ivy Lopez
  0 siblings, 0 replies; 5+ messages in thread
From: Ivy Lopez @ 2026-08-13  0:43 UTC (permalink / raw)
  To: sre; +Cc: linux-pm, linux-kernel

Apologies! This was sent to you by mistake due to a stale patch
file left in my outgoing queue. It's unrelated to the ds2760 series
and already correctly merged via a separate thread with Krzysztof
Kozlowski. Please disregard!

ivy

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

end of thread, other threads:[~2026-08-13  0:43 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-08 21:44 [PATCH] power: supply: ds2760_battery: fix NULL pointer dereference in w1_ds2760_remove_slave() Ivy Lopez
2026-08-12 22:00 ` Sebastian Reichel
2026-08-13  0:41 ` [PATCH v2] power: supply: ds2760_battery: convert to devm-managed workqueue and pm_notifier Ivy Lopez
2026-08-13  0:41   ` [PATCH] w1: fix spelling mistakes in comments across the subsystem Ivy Lopez
2026-08-13  0:43     ` Ivy Lopez

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