Linux kernel -stable discussions
 help / color / mirror / Atom feed
* [PATCH 01/21] leds: lm3532: Propagate error from devm_regulator_get()
       [not found] <20261021123406.3163547-1-lee@kernel.org>
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 03/21] leds: trigger: netdev: Hold RTNL lock across hw_control_get_device() in activate Lee Jones
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Dan Murphy, Jacek Anaszewski, linux-leds,
	linux-kernel
  Cc: stable

lm3532_parse_node() catches errors from devm_regulator_get() and sets
priv->regulator to NULL.  Because devm_regulator_get() already returns a
dummy regulator when the supply is omitted in Device Tree, an error
pointer is only returned on a genuine failure such as -EPROBE_DEFER.

Masking that error as NULL both breaks probe deferral when a supply is
specified and causes a NULL pointer dereference in regulator_enable()
and regulator_disable() when the LED brightness is later modified via
lm3532_led_enable() or lm3532_led_disable().

Propagate the error code from devm_regulator_get() instead.

Fixes: bc1b8492c764 ("leds: lm3532: Introduce the lm3532 LED driver")
Closes: https://sashiko.dev/#/bug/linux-8836989c-356e-4601-ac4c-6db97861cb00
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/leds-lm3532.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c
index b51496910b08..7f849a166a92 100644
--- a/drivers/leds/leds-lm3532.c
+++ b/drivers/leds/leds-lm3532.c
@@ -570,7 +570,7 @@ static int lm3532_parse_node(struct lm3532_data *priv)
 
 	priv->regulator = devm_regulator_get(&priv->client->dev, "vin");
 	if (IS_ERR(priv->regulator))
-		priv->regulator = NULL;
+		return PTR_ERR(priv->regulator);
 
 	ret = device_property_read_u32(&priv->client->dev, "ramp-up-us",
 				       &ramp_time);
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 03/21] leds: trigger: netdev: Hold RTNL lock across hw_control_get_device() in activate
       [not found] <20261021123406.3163547-1-lee@kernel.org>
  2026-10-21 12:32 ` [PATCH 01/21] leds: lm3532: Propagate error from devm_regulator_get() Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 04/21] leds: aw2013: Guard LED array index in aw2013_probe_dt() Lee Jones
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Ben Whitten, Oliver Jowett, Richard Purdie,
	Christian Marangi, David S. Miller, Andrew Lunn, linux-leds,
	linux-kernel
  Cc: stable

In netdev_trig_activate(), hw_control_get_device() is invoked without
holding rtnl_lock, and the returned struct device pointer is then
dereferenced via dev_name() and passed into set_device_name().

Because implementations such as phy_led_hw_control_get_device() and DSA
port LED callbacks return the embedded struct device of an attached
net_device without incrementing its reference count, a concurrent
network device unregistration or rename can detach and free the
net_device (or its kobject name) before set_device_name() copies the
name and acquires rtnl_lock, leading to a use-after-free.

Move rtnl_lock acquisition to the callers of set_device_name() so that
netdev_trig_activate() holds rtnl_lock across hw_control_get_device(),
dev_name(), and set_device_name().

Fixes: 0316cc5629d1 ("leds: trigger: netdev: init mode if hw control already active")
Closes: https://sashiko.dev/#/bug/linux-ef006cc6-9a69-46b2-ae9f-8de934d37aff
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/trigger/ledtrig-netdev.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index 5b0132484594..d69031bbd2b8 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -279,6 +279,8 @@ static int set_device_name(struct led_netdev_data *trigger_data,
 	struct net_device *new_dev = NULL;
 	char device_name[IFNAMSIZ];
 
+	ASSERT_RTNL();
+
 	if (size >= IFNAMSIZ)
 		return -EINVAL;
 
@@ -292,7 +294,6 @@ static int set_device_name(struct led_netdev_data *trigger_data,
 	/*
 	 * Lock order: rtnl_lock -> netdev instance lock -> trigger_data lock.
 	 */
-	rtnl_lock();
 	if (device_name[0]) {
 		new_dev = dev_get_by_name(&init_net, device_name);
 		if (new_dev)
@@ -319,7 +320,6 @@ static int set_device_name(struct led_netdev_data *trigger_data,
 	mutex_unlock(&trigger_data->lock);
 	if (new_dev)
 		netdev_unlock_ops(new_dev);
-	rtnl_unlock();
 
 	return 0;
 }
@@ -331,7 +331,9 @@ static ssize_t device_name_store(struct device *dev,
 	struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
 	int ret;
 
+	rtnl_lock();
 	ret = set_device_name(trigger_data, buf, size);
+	rtnl_unlock();
 
 	if (ret < 0)
 		return ret;
@@ -760,6 +762,7 @@ static int netdev_trig_activate(struct led_classdev *led_cdev)
 	 * Init already enabled mode in hw control.
 	 */
 	if (supports_hw_control(led_cdev)) {
+		rtnl_lock();
 		dev = led_cdev->hw_control_get_device(led_cdev);
 		if (dev) {
 			const char *name = dev_name(dev);
@@ -771,6 +774,7 @@ static int netdev_trig_activate(struct led_classdev *led_cdev)
 			if (!rc)
 				trigger_data->mode = mode;
 		}
+		rtnl_unlock();
 	}
 
 	led_set_trigger_data(led_cdev, trigger_data);
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 04/21] leds: aw2013: Guard LED array index in aw2013_probe_dt()
       [not found] <20261021123406.3163547-1-lee@kernel.org>
  2026-10-21 12:32 ` [PATCH 01/21] leds: lm3532: Propagate error from devm_regulator_get() Lee Jones
  2026-10-21 12:32 ` [PATCH 03/21] leds: trigger: netdev: Hold RTNL lock across hw_control_get_device() in activate Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-27 14:27   ` Nikita Travkin
  2026-10-21 12:32 ` [PATCH 05/21] leds: pca955x: Take a reference on the child firmware node Lee Jones
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Nikita Travkin, linux-leds, linux-kernel; +Cc: stable

aw2013_probe_dt() validates the initial child node count against
AW2013_MAX_LEDS via of_get_available_child_count() before iterating over
available child nodes with for_each_available_child_of_node_scoped().

Add an explicit bounds check on the loop index before indexing into
chip->leds[] to ensure the statically sized array cannot be overrun if
additional child nodes become available during iteration.

Fixes: 59ea3c9faf32 ("leds: add aw2013 driver")
Closes: https://sashiko.dev/#/bug/linux-577a1fa0-4e80-42cc-8c7f-34c43c131d95
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/leds-aw2013.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c
index 216755d6010f..dfeac8b2993f 100644
--- a/drivers/leds/leds-aw2013.c
+++ b/drivers/leds/leds-aw2013.c
@@ -286,6 +286,9 @@ static int aw2013_probe_dt(struct aw2013 *chip)
 			continue;
 		}
 
+		if (i >= AW2013_MAX_LEDS)
+			return -EINVAL;
+
 		led = &chip->leds[i];
 		led->num = source;
 		led->chip = chip;
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 05/21] leds: pca955x: Take a reference on the child firmware node
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (2 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 04/21] leds: aw2013: Guard LED array index in aw2013_probe_dt() Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 06/21] leds: lp50xx: Guard sub-LED count in lp50xx_probe_dt() Lee Jones
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Nate Case, Eddie James, linux-leds,
	linux-kernel; +Cc: stable

pca955x_get_pdata() caches each child fwnode in led->fwnode while
iterating over the device's child nodes with
device_for_each_child_node(), which drops its reference on each child
node when advancing to the next iteration or finishing the loop.
Because the LED core stores init_data.fwnode via device_set_node()
without taking an additional reference of its own, dynamically
allocated firmware nodes can be freed before or while the LED class
device uses them.

Acquire a reference with fwnode_handle_get() when caching child in
led->fwnode and register a devm action to release it when the device is
unbound or probe fails.

Fixes: 7c4815929276 ("leds: pca955x: Let the core process the fwnode")
Closes: https://sashiko.dev/#/bug/linux-a78a30d3-e8c1-43eb-af6c-c26279dc21e7
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/leds-pca955x.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 273383351ba0..70043e0e6f08 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -530,12 +530,16 @@ static int pca955x_gpio_direction_output(struct gpio_chip *gc,
 }
 #endif /* CONFIG_LEDS_PCA955X_GPIO */
 
+static void pca955x_fwnode_put(void *data)
+{
+	fwnode_handle_put(data);
+}
+
 static struct pca955x_platform_data *
 pca955x_get_pdata(struct i2c_client *client, const struct pca955x_chipdef *chip)
 {
 	struct pca955x_platform_data *pdata;
 	struct pca955x_led *led;
-	struct fwnode_handle *child;
 	int count;
 
 	count = device_get_child_node_count(&client->dev);
@@ -552,7 +556,7 @@ pca955x_get_pdata(struct i2c_client *client, const struct pca955x_chipdef *chip)
 	if (!pdata->leds)
 		return ERR_PTR(-ENOMEM);
 
-	device_for_each_child_node(&client->dev, child) {
+	device_for_each_child_node_scoped(&client->dev, child) {
 		u32 reg;
 		int res;
 
@@ -561,8 +565,17 @@ pca955x_get_pdata(struct i2c_client *client, const struct pca955x_chipdef *chip)
 			continue;
 
 		led = &pdata->leds[reg];
+		if (led->fwnode)
+			devm_release_action(&client->dev, pca955x_fwnode_put,
+					    led->fwnode);
 		led->type = PCA955X_TYPE_LED;
-		led->fwnode = child;
+		led->fwnode = fwnode_handle_get(child);
+
+		res = devm_add_action_or_reset(&client->dev, pca955x_fwnode_put,
+					       led->fwnode);
+		if (res)
+			return ERR_PTR(res);
+
 		led->default_state = led_init_default_state_get(child);
 
 		fwnode_property_read_u32(child, "type", &led->type);
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 06/21] leds: lp50xx: Guard sub-LED count in lp50xx_probe_dt()
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (3 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 05/21] leds: pca955x: Take a reference on the child firmware node Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 07/21] leds: trigger: netdev: Serialise work cancellation and state updates Lee Jones
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Christian Hitz, Dan Murphy, Jacek Anaszewski,
	linux-leds, linux-kernel
  Cc: stable

lp50xx_probe_dt() allocates mc_led_info with LP50XX_LEDS_PER_MODULE (3)
elements and increments num_colors for each sub-LED child node without
checking whether num_colors has already reached LP50XX_LEDS_PER_MODULE.
If a device tree specifies more than three sub-LED child nodes with
valid reg properties, led->mc_cdev.num_colors exceeds the capacity of
the subled_info array, causing out-of-bounds accesses during brightness
and intensity updates.

Return -EINVAL if num_colors reaches LP50XX_LEDS_PER_MODULE when
iterating over sub-LED child nodes.

Fixes: 242b81170fb8 ("leds: lp50xx: Add the LP50XX family of the RGB LED driver")
Closes: https://sashiko.dev/#/bug/linux-a0c116ab-2f34-4f53-a007-d7a42f28677b
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/leds-lp50xx.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/leds/leds-lp50xx.c b/drivers/leds/leds-lp50xx.c
index 20bfb315bda1..32b0d802d474 100644
--- a/drivers/leds/leds-lp50xx.c
+++ b/drivers/leds/leds-lp50xx.c
@@ -507,6 +507,14 @@ static int lp50xx_probe_dt(struct lp50xx *priv)
 
 		fwnode_for_each_child_node(child, led_node) {
 			int multi_index;
+
+			if (num_colors >= LP50XX_LEDS_PER_MODULE) {
+				fwnode_handle_put(led_node);
+				return dev_err_probe(priv->dev, -EINVAL,
+						     "Too many sub-LEDs (max %d)\n",
+						     LP50XX_LEDS_PER_MODULE);
+			}
+
 			ret = fwnode_property_read_u32(led_node, "color",
 						       &color_id);
 			if (ret) {
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 07/21] leds: trigger: netdev: Serialise work cancellation and state updates
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (4 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 06/21] leds: lp50xx: Guard sub-LED count in lp50xx_probe_dt() Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 08/21] leds: sgm3140: Replace powerdown timer with delayed work Lee Jones
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Ben Whitten, Oliver Jowett, Richard Purdie,
	Jacek Anaszewski, linux-leds, linux-kernel
  Cc: stable

set_device_name() and netdev_trig_notify() cancel trigger_data->work
before acquiring trigger_data->lock, whilst netdev_led_attr_store() and
interval_store() cancel trigger_data->work, update trigger_data state,
and call set_baseline_state() without holding trigger_data->lock at all.

Because set_baseline_state() can re-arm trigger_data->work outside the
lock, a concurrent notifier or sysfs store can re-schedule
netdev_trig_work() after cancel_delayed_work_sync() has returned and
whilst set_device_name() or netdev_trig_notify() is replacing or
dropping trigger_data->net_dev, leading to a use-after-free in
netdev_trig_work().

Move cancel_delayed_work_sync() inside trigger_data->lock in
set_device_name() and netdev_trig_notify(), and hold trigger_data->lock
across work cancellation, state updates, and set_baseline_state() in
netdev_led_attr_store() and interval_store().

Fixes: 06f502f57d0d ("leds: trigger: Introduce a NETDEV trigger")
Closes: https://sashiko.dev/#/bug/linux-b2b6c3bb-8017-4623-94d4-2999efa6a663
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/trigger/ledtrig-netdev.c | 35 +++++++++++++++++++--------
 1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index d69031bbd2b8..9fa56ac523c7 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -284,8 +284,6 @@ static int set_device_name(struct led_netdev_data *trigger_data,
 	if (size >= IFNAMSIZ)
 		return -EINVAL;
 
-	cancel_delayed_work_sync(&trigger_data->work);
-
 	memcpy(device_name, name, size);
 	device_name[size] = 0;
 	if (size > 0 && device_name[size - 1] == '\n')
@@ -301,6 +299,8 @@ static int set_device_name(struct led_netdev_data *trigger_data,
 	}
 	mutex_lock(&trigger_data->lock);
 
+	cancel_delayed_work_sync(&trigger_data->work);
+
 	dev_put(trigger_data->net_dev);
 	trigger_data->net_dev = new_dev;
 	strscpy(trigger_data->device_name, device_name);
@@ -384,7 +384,7 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
 {
 	struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
 	struct led_classdev *led_cdev = trigger_data->led_cdev;
-	unsigned long state, mode = trigger_data->mode;
+	unsigned long state, mode;
 	int ret;
 	int bit;
 
@@ -416,6 +416,9 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
 		return -EINVAL;
 	}
 
+	mutex_lock(&trigger_data->lock);
+
+	mode = trigger_data->mode;
 	assign_bit(bit, &mode, state);
 
 	if (test_bit(TRIGGER_NETDEV_LINK, &mode) &&
@@ -428,8 +431,10 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
 	     test_bit(TRIGGER_NETDEV_LINK_25000, &mode) ||
 	     test_bit(TRIGGER_NETDEV_LINK_40000, &mode) ||
 	     test_bit(TRIGGER_NETDEV_LINK_50000, &mode) ||
-	     test_bit(TRIGGER_NETDEV_LINK_100000, &mode)))
+	     test_bit(TRIGGER_NETDEV_LINK_100000, &mode))) {
+		mutex_unlock(&trigger_data->lock);
 		return -EINVAL;
+	}
 
 	cancel_delayed_work_sync(&trigger_data->work);
 
@@ -437,11 +442,15 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
 	trigger_data->hw_control = can_hw_control(trigger_data);
 
 	if (!led_cdev->brightness_set && !led_cdev->brightness_set_blocking &&
-	    !trigger_data->hw_control)
+	    !trigger_data->hw_control) {
+		mutex_unlock(&trigger_data->lock);
 		return -EOPNOTSUPP;
+	}
 
 	set_baseline_state(trigger_data);
 
+	mutex_unlock(&trigger_data->lock);
+
 	return size;
 }
 
@@ -493,13 +502,17 @@ static ssize_t interval_store(struct device *dev,
 	unsigned long value;
 	int ret;
 
-	if (trigger_data->hw_control)
-		return -EINVAL;
-
 	ret = kstrtoul(buf, 0, &value);
 	if (ret)
 		return ret;
 
+	mutex_lock(&trigger_data->lock);
+
+	if (trigger_data->hw_control) {
+		mutex_unlock(&trigger_data->lock);
+		return -EINVAL;
+	}
+
 	/* impose some basic bounds on the timer interval */
 	if (value >= 5 && value <= 10000) {
 		cancel_delayed_work_sync(&trigger_data->work);
@@ -508,6 +521,8 @@ static ssize_t interval_store(struct device *dev,
 		set_baseline_state(trigger_data);	/* resets timer */
 	}
 
+	mutex_unlock(&trigger_data->lock);
+
 	return size;
 }
 
@@ -628,10 +643,10 @@ static int netdev_trig_notify(struct notifier_block *nb,
 	      (evt == NETDEV_REGISTER && !strcmp(dev->name, trigger_data->device_name))))
 		return NOTIFY_DONE;
 
-	cancel_delayed_work_sync(&trigger_data->work);
-
 	mutex_lock(&trigger_data->lock);
 
+	cancel_delayed_work_sync(&trigger_data->work);
+
 	trigger_data->carrier_link_up = false;
 	trigger_data->link_speed = SPEED_UNKNOWN;
 	trigger_data->duplex = DUPLEX_UNKNOWN;
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 08/21] leds: sgm3140: Replace powerdown timer with delayed work
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (5 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 07/21] leds: trigger: netdev: Serialise work cancellation and state updates Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 09/21] leds: sgm3140: Cancel powerdown work via devres after LED unregistration Lee Jones
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Luca Weiss, linux-leds, linux-kernel; +Cc: stable

sgm3140_powerdown_timer() runs in atomic timer softirq context and calls
regulator_disable(), which acquires sleepable mutexes, as well as
gpiod_set_value() on GPIOs that are otherwise driven via
gpiod_set_value_cansleep().

Replace powerdown_timer with a delayed_work item so that the powerdown
sequence executes in process context and can safely sleep when disabling
the regulator and driving the GPIOs.

Fixes: cef8ec8cbd21 ("leds: add sgm3140 driver")
Closes: https://sashiko.dev/#/bug/linux-8c3788a3-17f9-49dc-89be-c9f5844b0b95
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/flash/leds-sgm3140.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/leds/flash/leds-sgm3140.c b/drivers/leds/flash/leds-sgm3140.c
index dc6840357370..478573da1d61 100644
--- a/drivers/leds/flash/leds-sgm3140.c
+++ b/drivers/leds/flash/leds-sgm3140.c
@@ -6,6 +6,7 @@
 #include <linux/module.h>
 #include <linux/regulator/consumer.h>
 #include <linux/platform_device.h>
+#include <linux/workqueue.h>
 
 #include <media/v4l2-flash-led-class.h>
 
@@ -16,7 +17,7 @@ struct sgm3140 {
 	struct led_classdev_flash fled_cdev;
 	struct v4l2_flash *v4l2_flash;
 
-	struct timer_list powerdown_timer;
+	struct delayed_work powerdown_work;
 
 	struct gpio_desc *flash_gpio;
 	struct gpio_desc *enable_gpio;
@@ -52,10 +53,10 @@ static int sgm3140_strobe_set(struct led_classdev_flash *fled_cdev, bool state)
 		}
 		gpiod_set_value_cansleep(priv->flash_gpio, 1);
 		gpiod_set_value_cansleep(priv->enable_gpio, 1);
-		mod_timer(&priv->powerdown_timer,
-			  jiffies + usecs_to_jiffies(priv->timeout));
+		schedule_delayed_work(&priv->powerdown_work,
+				      usecs_to_jiffies(priv->timeout));
 	} else {
-		timer_delete_sync(&priv->powerdown_timer);
+		cancel_delayed_work_sync(&priv->powerdown_work);
 		gpiod_set_value_cansleep(priv->enable_gpio, 0);
 		gpiod_set_value_cansleep(priv->flash_gpio, 0);
 		ret = regulator_disable(priv->vin_regulator);
@@ -75,7 +76,7 @@ static int sgm3140_strobe_get(struct led_classdev_flash *fled_cdev, bool *state)
 {
 	struct sgm3140 *priv = flcdev_to_sgm3140(fled_cdev);
 
-	*state = timer_pending(&priv->powerdown_timer);
+	*state = delayed_work_pending(&priv->powerdown_work);
 
 	return 0;
 }
@@ -117,7 +118,7 @@ static int sgm3140_brightness_set(struct led_classdev *led_cdev,
 		gpiod_set_value_cansleep(priv->flash_gpio, 0);
 		gpiod_set_value_cansleep(priv->enable_gpio, 1);
 	} else {
-		timer_delete_sync(&priv->powerdown_timer);
+		cancel_delayed_work_sync(&priv->powerdown_work);
 		gpiod_set_value_cansleep(priv->flash_gpio, 0);
 		gpiod_set_value_cansleep(priv->enable_gpio, 0);
 		ret = regulator_disable(priv->vin_regulator);
@@ -133,12 +134,13 @@ static int sgm3140_brightness_set(struct led_classdev *led_cdev,
 	return 0;
 }
 
-static void sgm3140_powerdown_timer(struct timer_list *t)
+static void sgm3140_powerdown_work(struct work_struct *work)
 {
-	struct sgm3140 *priv = timer_container_of(priv, t, powerdown_timer);
+	struct sgm3140 *priv = container_of(work, struct sgm3140,
+					    powerdown_work.work);
 
-	gpiod_set_value(priv->enable_gpio, 0);
-	gpiod_set_value(priv->flash_gpio, 0);
+	gpiod_set_value_cansleep(priv->enable_gpio, 0);
+	gpiod_set_value_cansleep(priv->flash_gpio, 0);
 	regulator_disable(priv->vin_regulator);
 
 	priv->enabled = false;
@@ -235,7 +237,7 @@ static int sgm3140_probe(struct platform_device *pdev)
 	 */
 	priv->timeout = min(priv->max_timeout, FLASH_TIMEOUT_DEFAULT);
 
-	timer_setup(&priv->powerdown_timer, sgm3140_powerdown_timer, 0);
+	INIT_DELAYED_WORK(&priv->powerdown_work, sgm3140_powerdown_work);
 
 	fled_cdev = &priv->fled_cdev;
 	led_cdev = &fled_cdev->led_cdev;
@@ -284,7 +286,7 @@ static void sgm3140_remove(struct platform_device *pdev)
 {
 	struct sgm3140 *priv = platform_get_drvdata(pdev);
 
-	timer_delete_sync(&priv->powerdown_timer);
+	cancel_delayed_work_sync(&priv->powerdown_work);
 
 	v4l2_flash_release(priv->v4l2_flash);
 }
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 09/21] leds: sgm3140: Cancel powerdown work via devres after LED unregistration
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (6 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 08/21] leds: sgm3140: Replace powerdown timer with delayed work Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 10/21] leds: class: Initialise trigger_lock before exposing sysfs attributes Lee Jones
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Luca Weiss, linux-leds, linux-kernel; +Cc: stable

Because devm_led_classdev_flash_register_ext() unregisters the flash LED
device via devres after sgm3140_remove() returns, cancelling
powerdown_work manually in sgm3140_remove() leaves a window where a
concurrent sysfs write to flash_strobe can re-arm powerdown_work before
the LED class device is unregistered and priv is freed.  A similar
window exists in sgm3140_probe() if v4l2_flash_init() fails after the
LED class device has been registered.

Initialise powerdown_work with devm_delayed_work_autocancel() before
calling devm_led_classdev_flash_register_ext() so that devres cancels
the work after unregistering the LED class device and before releasing
the regulator, GPIOs, and driver data.

Fixes: cef8ec8cbd21 ("leds: add sgm3140 driver")
Closes: https://sashiko.dev/#/bug/linux-81468d52-b80d-46b5-b1b4-29c35e9acb21
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/flash/leds-sgm3140.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/leds/flash/leds-sgm3140.c b/drivers/leds/flash/leds-sgm3140.c
index 478573da1d61..4e21144900c9 100644
--- a/drivers/leds/flash/leds-sgm3140.c
+++ b/drivers/leds/flash/leds-sgm3140.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 // Copyright (C) 2020 Luca Weiss <luca@z3ntu.xyz>
 
+#include <linux/devm-helpers.h>
 #include <linux/gpio/consumer.h>
 #include <linux/led-class-flash.h>
 #include <linux/module.h>
@@ -237,7 +238,10 @@ static int sgm3140_probe(struct platform_device *pdev)
 	 */
 	priv->timeout = min(priv->max_timeout, FLASH_TIMEOUT_DEFAULT);
 
-	INIT_DELAYED_WORK(&priv->powerdown_work, sgm3140_powerdown_work);
+	ret = devm_delayed_work_autocancel(&pdev->dev, &priv->powerdown_work,
+					   sgm3140_powerdown_work);
+	if (ret)
+		goto err;
 
 	fled_cdev = &priv->fled_cdev;
 	led_cdev = &fled_cdev->led_cdev;
@@ -286,8 +290,6 @@ static void sgm3140_remove(struct platform_device *pdev)
 {
 	struct sgm3140 *priv = platform_get_drvdata(pdev);
 
-	cancel_delayed_work_sync(&priv->powerdown_work);
-
 	v4l2_flash_release(priv->v4l2_flash);
 }
 
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 10/21] leds: class: Initialise trigger_lock before exposing sysfs attributes
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (7 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 09/21] leds: sgm3140: Cancel powerdown work via devres after LED unregistration Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 11/21] leds: class: Unlock led_access before unregistering device on error Lee Jones
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, John Lenz, Richard Purdie, Florian Fainelli,
	linux-leds, linux-kernel
  Cc: stable

led_classdev_register_ext() calls device_create_with_groups(), which
creates the LED trigger sysfs attributes and emits the KOBJ_ADD uevent,
before initialising led_cdev->trigger_lock with init_rwsem().

Because trigger_read() and trigger_may_offload_to_hw_show() acquire
led_cdev->trigger_lock without holding led_cdev->led_access, a
concurrent sysfs read during registration can call down_read() on an
uninitialised rw_semaphore.

Initialise led_cdev->trigger_lock before calling
device_create_with_groups().

Fixes: 14b5d6dd40b3 ("leds: Fix race between LED device uevent and actual attributes creation")
Closes: https://sashiko.dev/#/bug/linux-376c7db5-ddc1-4faa-9f5b-43d2d3b7cb0d
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/led-class.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 00be3cb96c00..2a3040fa3c4b 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -532,6 +532,9 @@ int led_classdev_register_ext(struct device *parent,
 	if (led_cdev->color >= LED_COLOR_ID_MAX)
 		dev_warn(parent, "LED %s color identifier out of range\n", final_name);
 
+#ifdef CONFIG_LEDS_TRIGGERS
+	init_rwsem(&led_cdev->trigger_lock);
+#endif
 	mutex_init(&led_cdev->led_access);
 	mutex_lock(&led_cdev->led_access);
 	led_cdev->dev = device_create_with_groups(&leds_class, parent, 0,
@@ -554,9 +557,6 @@ int led_classdev_register_ext(struct device *parent,
 	}
 
 	led_cdev->work_flags = 0;
-#ifdef CONFIG_LEDS_TRIGGERS
-	init_rwsem(&led_cdev->trigger_lock);
-#endif
 #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
 	led_cdev->brightness_hw_changed = -1;
 #endif
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 11/21] leds: class: Unlock led_access before unregistering device on error
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (8 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 10/21] leds: class: Initialise trigger_lock before exposing sysfs attributes Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 12/21] leds: aat1290: Retain child device_node reference for device lifetime Lee Jones
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, John Lenz, Richard Purdie, Jacek Anaszewski,
	Luis Henriques, linux-leds, linux-kernel
  Cc: stable

In led_classdev_register_ext(), if led_add_brightness_hw_changed() fails
after device_create_with_groups() has exposed the LED sysfs attributes,
calling device_unregister() while holding led_cdev->led_access can
cause an AB-BA deadlock with a concurrent sysfs access that holds an
active kernfs reference and blocks on led_cdev->led_access.

Disable sysfs writes and release led_cdev->led_access before calling
device_unregister() on the error path.

Fixes: 6d71021ab3b0 ("leds: class: ensure workqueue is initialized before setting brightness")
Closes: https://sashiko.dev/#/bug/linux-400d8d29-9e78-4fb7-af37-b07c92bdf4df
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/led-class.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 2a3040fa3c4b..c8529003dbe1 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -549,9 +549,10 @@ int led_classdev_register_ext(struct device *parent,
 	if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) {
 		ret = led_add_brightness_hw_changed(led_cdev);
 		if (ret) {
+			led_sysfs_disable(led_cdev);
+			mutex_unlock(&led_cdev->led_access);
 			device_unregister(led_cdev->dev);
 			led_cdev->dev = NULL;
-			mutex_unlock(&led_cdev->led_access);
 			return ret;
 		}
 	}
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 12/21] leds: aat1290: Retain child device_node reference for device lifetime
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (9 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 11/21] leds: class: Unlock led_access before unregistering device on error Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 13/21] leds: aat1290: Prevent out-of-bounds read in aat1290_brightness_to_intensity() Lee Jones
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Jacek Anaszewski, Bryan Wu, Kyungmin Park,
	Krzysztof Kozlowski, linux-leds, linux-kernel
  Cc: stable

aat1290_led_parse_dt() acquires a child device_node with the
__free(device_node) cleanup attribute and assigns it directly to the
*sub_node output parameter without consuming the pointer via
no_free_ptr().  Consequently, of_node_put() is called automatically when
aat1290_led_parse_dt() returns, leaving aat1290_led_probe() with a
dangling pointer when it passes the firmware node to
led_classdev_flash_register_ext() and v4l2_flash_init().

Because the LED core stores init_data.fwnode via device_set_node()
without taking an additional reference of its own, consume child_node
with no_free_ptr() and register a devm action to release the reference
when the device is unbound or probe fails.

Fixes: ac69b9038f82 ("leds: aat1290: add support for V4L2 Flash sub-device")
Fixes: 1e63395e58b2 ("leds: aat1290: Use scoped device node handling to simplify error paths")
Closes: https://sashiko.dev/#/bug/linux-2255c65e-840f-49ab-9dc5-227a4eab4c37
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/flash/leds-aat1290.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/leds/flash/leds-aat1290.c b/drivers/leds/flash/leds-aat1290.c
index 4bde0b07fe78..ea9af6c3fbf4 100644
--- a/drivers/leds/flash/leds-aat1290.c
+++ b/drivers/leds/flash/leds-aat1290.c
@@ -211,6 +211,11 @@ static int aat1290_led_flash_timeout_set(struct led_classdev_flash *fled_cdev,
 	return 0;
 }
 
+static void aat1290_of_node_put(void *data)
+{
+	of_node_put(data);
+}
+
 static int aat1290_led_parse_dt(struct aat1290_led *led,
 			struct aat1290_led_config_data *cfg,
 			struct device_node **sub_node)
@@ -279,9 +284,9 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
 		return ret;
 	}
 
-	*sub_node = child_node;
+	*sub_node = no_free_ptr(child_node);
 
-	return 0;
+	return devm_add_action_or_reset(dev, aat1290_of_node_put, *sub_node);
 }
 
 static void aat1290_led_validate_mm_current(struct aat1290_led *led,
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 13/21] leds: aat1290: Prevent out-of-bounds read in aat1290_brightness_to_intensity()
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (10 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 12/21] leds: aat1290: Retain child device_node reference for device lifetime Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 14/21] leds: flash: Avoid divide-by-zero in led_clamp_align() Lee Jones
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Jacek Anaszewski, Kyungmin Park, Bryan Wu,
	linux-leds, linux-kernel
  Cc: stable

When a flash strobe event or external strobe update resets
led_cdev->brightness to LED_OFF (0), a subsequent V4L2 torch intensity
query passes brightness == 0 to aat1290_brightness_to_intensity().
Subtracting 1 unconditionally indexes led->mm_current_scale[-1] out of
bounds.

Return 0 when brightness is LED_OFF before indexing mm_current_scale.

Fixes: ac69b9038f82 ("leds: aat1290: add support for V4L2 Flash sub-device")
Closes: https://sashiko.dev/#/bug/linux-9e7db3d9-0ea0-42f2-8027-01aa467d3a7d
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/flash/leds-aat1290.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/leds/flash/leds-aat1290.c b/drivers/leds/flash/leds-aat1290.c
index ea9af6c3fbf4..223bbba9114f 100644
--- a/drivers/leds/flash/leds-aat1290.c
+++ b/drivers/leds/flash/leds-aat1290.c
@@ -393,6 +393,9 @@ static s32 aat1290_brightness_to_intensity(struct v4l2_flash *v4l2_flash,
 	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
 	struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
 
+	if (brightness == LED_OFF)
+		return 0;
+
 	return led->mm_current_scale[brightness - 1];
 }
 
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 14/21] leds: flash: Avoid divide-by-zero in led_clamp_align()
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (11 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 13/21] leds: aat1290: Prevent out-of-bounds read in aat1290_brightness_to_intensity() Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-22 19:20   ` Jacek Anaszewski
  2026-10-22 21:00   ` David Laight
  2026-10-21 12:32 ` [PATCH 15/21] leds: lm3532: Validate LED string indices in lm3532_parse_node() Lee Jones
                   ` (6 subsequent siblings)
  19 siblings, 2 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Dmitry Antipov, Jacek Anaszewski, Bryan Wu,
	Kyungmin Park, linux-leds, linux-kernel
  Cc: stable

If a flash LED driver leaves a setting's step size as zero, writing to
the corresponding sysfs attribute invokes led_clamp_align() and triggers
an integer division by zero when aligning the offset to s->step.

Clamp s->val to [s->min, s->max] and return early when s->step is zero.

Fixes: 7aea8389a77a ("leds: Add LED Flash class extension to the LED subsystem")
Closes: https://sashiko.dev/#/bug/linux-9d06d7fe-310b-4aee-8b16-0fb49550c287
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/led-class-flash.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
index 181dfd49c6ad..16b3b6b9365b 100644
--- a/drivers/leds/led-class-flash.c
+++ b/drivers/leds/led-class-flash.c
@@ -375,6 +375,11 @@ static void led_clamp_align(struct led_flash_setting *s)
 {
 	u32 v, offset;
 
+	if (!s->step) {
+		s->val = clamp(s->val, s->min, s->max);
+		return;
+	}
+
 	v = s->val + s->step / 2;
 	v = clamp(v, s->min, s->max);
 	offset = v - s->min;
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 15/21] leds: lm3532: Validate LED string indices in lm3532_parse_node()
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (12 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 14/21] leds: flash: Avoid divide-by-zero in led_clamp_align() Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 16/21] leds: lm3532: Clamp full-scale current to minimum bound Lee Jones
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Dan Murphy, Jacek Anaszewski, linux-leds,
	linux-kernel
  Cc: stable

lm3532_parse_node() reads the led-sources property into led->led_strings
without bounding the individual string indices.  If a firmware node
specifies an index of LM3532_MAX_LED_STRINGS or greater,
lm3532_init_registers() shifts beyond the hardware output configuration
fields and, for values of 16 or greater, triggers a 32-bit
shift-out-of-bounds.

Reject LED string indices >= LM3532_MAX_LED_STRINGS with -EINVAL when
parsing the firmware node.

Fixes: bc1b8492c764 ("leds: lm3532: Introduce the lm3532 LED driver")
Closes: https://sashiko.dev/#/bug/linux-f6f7a3f6-4dc4-46b4-84e3-c26fc9099572
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/leds-lm3532.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c
index cfad4e791e4b..6fe752889487 100644
--- a/drivers/leds/leds-lm3532.c
+++ b/drivers/leds/leds-lm3532.c
@@ -649,6 +649,11 @@ static int lm3532_parse_node(struct lm3532_data *priv)
 			return ret;
 		}
 
+		for (int j = 0; j < led->num_leds; j++) {
+			if (led->led_strings[j] >= LM3532_MAX_LED_STRINGS)
+				return -EINVAL;
+		}
+
 		led->priv = priv;
 		led->led_dev.brightness_set_blocking = lm3532_brightness_set;
 
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 16/21] leds: lm3532: Clamp full-scale current to minimum bound
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (13 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 15/21] leds: lm3532: Validate LED string indices in lm3532_parse_node() Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 17/21] leds: aat1290: Avoid leaking devres pinctrl handles on strobe source changes Lee Jones
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Dan Murphy, Jacek Anaszewski, linux-leds,
	linux-kernel
  Cc: stable

lm3532_parse_node() bounds led->full_scale_current to LM3532_FS_CURR_MAX
using min(), but does not enforce the lower bound LM3532_FS_CURR_MIN.
If a firmware node specifies led-max-microamp between 1 and
LM3532_FS_CURR_MIN - 1, subtracting LM3532_FS_CURR_MIN in
lm3532_init_registers() underflows and writes a corrupted full-scale
current register value.

Use clamp() when led-max-microamp is present so led->full_scale_current
is bounded to [LM3532_FS_CURR_MIN, LM3532_FS_CURR_MAX].

Fixes: 517ea49a7b23 ("leds: lm3532: Add full scale current configuration")
Closes: https://sashiko.dev/#/bug/linux-114b6c69-6d76-4f4d-bb87-0980b1e15bbd
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/leds-lm3532.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c
index 6fe752889487..327460de2ff8 100644
--- a/drivers/leds/leds-lm3532.c
+++ b/drivers/leds/leds-lm3532.c
@@ -615,14 +615,16 @@ static int lm3532_parse_node(struct lm3532_data *priv)
 			return ret;
 		}
 
-		if (fwnode_property_present(child, "led-max-microamp") &&
-		    fwnode_property_read_u32(child, "led-max-microamp",
-					     &led->full_scale_current))
-			dev_err(&priv->client->dev,
-				"Failed getting led-max-microamp\n");
-		else
-			led->full_scale_current = min(led->full_scale_current,
-						      LM3532_FS_CURR_MAX);
+		if (fwnode_property_present(child, "led-max-microamp")) {
+			if (fwnode_property_read_u32(child, "led-max-microamp",
+						     &led->full_scale_current))
+				dev_err(&priv->client->dev,
+					"Failed getting led-max-microamp\n");
+			else
+				led->full_scale_current = clamp(led->full_scale_current,
+								LM3532_FS_CURR_MIN,
+								LM3532_FS_CURR_MAX);
+		}
 
 		if (led->mode == LM3532_BL_MODE_ALS) {
 			led->mode = LM3532_ALS_CTRL;
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 17/21] leds: aat1290: Avoid leaking devres pinctrl handles on strobe source changes
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (14 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 16/21] leds: lm3532: Clamp full-scale current to minimum bound Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 18/21] leds: aw2013: Unlock chip mutex before registering LEDs Lee Jones
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Jacek Anaszewski, Kyungmin Park, Bryan Wu,
	linux-leds, linux-kernel
  Cc: stable

aat1290_led_external_strobe_set() is a runtime V4L2 control callback
that calls devm_pinctrl_get_select() every time the strobe source is
switched.  Because devm_pinctrl_get() allocates a new devres entry and
takes an additional pinctrl reference on each call, repeated updates to
V4L2_CID_FLASH_STROBE_SOURCE leak memory and pinctrl references for the
lifetime of the device.

Use pinctrl_get_select() followed by pinctrl_put() instead, as the
device's underlying pinctrl instance is already held across the device
lifetime.

Fixes: ac69b9038f82 ("leds: aat1290: add support for V4L2 Flash sub-device")
Closes: https://sashiko.dev/#/bug/linux-e1e22682-0cb6-4dcc-9a7f-01993691f7b0
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/flash/leds-aat1290.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/leds/flash/leds-aat1290.c b/drivers/leds/flash/leds-aat1290.c
index 223bbba9114f..fc7904966183 100644
--- a/drivers/leds/flash/leds-aat1290.c
+++ b/drivers/leds/flash/leds-aat1290.c
@@ -413,13 +413,15 @@ static int aat1290_led_external_strobe_set(struct v4l2_flash *v4l2_flash,
 	led->movie_mode = false;
 	led_cdev->brightness = 0;
 
-	pinctrl = devm_pinctrl_get_select(&led->pdev->dev,
-						enable ? "isp" : "host");
+	pinctrl = pinctrl_get_select(&led->pdev->dev,
+				     enable ? "isp" : "host");
 	if (IS_ERR(pinctrl)) {
 		dev_warn(&led->pdev->dev, "Unable to switch strobe source.\n");
 		return PTR_ERR(pinctrl);
 	}
 
+	pinctrl_put(pinctrl);
+
 	return 0;
 }
 
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 18/21] leds: aw2013: Unlock chip mutex before registering LEDs
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (15 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 17/21] leds: aat1290: Avoid leaking devres pinctrl handles on strobe source changes Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-27 14:28   ` Nikita Travkin
  2026-10-21 12:32 ` [PATCH 19/21] leds: is31fl32xx: Clamp channel current limit in is31fl3293_reset() Lee Jones
                   ` (2 subsequent siblings)
  19 siblings, 1 reply; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Nikita Travkin, linux-leds, linux-kernel; +Cc: stable

aw2013_probe() holds chip->mutex across aw2013_probe_dt(), which calls
devm_led_classdev_register_ext().  When a default trigger such as
"timer" is configured on an LED in the Device Tree, the LED core
synchronously activates the trigger during registration and invokes
aw2013_blink_set() on the same thread, which attempts to acquire
chip->mutex and deadlocks.

Reset the chip, disable the regulators, and release chip->mutex in
aw2013_probe() before calling aw2013_probe_dt(), and update
chip->num_leds before each LED is registered so trigger callbacks can
enable the chip cleanly during registration.

Fixes: 59ea3c9faf32 ("leds: add aw2013 driver")
Closes: https://sashiko.dev/#/bug/linux-5e2c9083-b95b-4aa4-aa0a-b0be8865ff12
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/leds-aw2013.c | 54 ++++++++++++++++++++++----------------
 1 file changed, 32 insertions(+), 22 deletions(-)

diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c
index dfeac8b2993f..c947cd068963 100644
--- a/drivers/leds/leds-aw2013.c
+++ b/drivers/leds/leds-aw2013.c
@@ -271,8 +271,6 @@ static int aw2013_probe_dt(struct aw2013 *chip)
 	if (!count || count > AW2013_MAX_LEDS)
 		return -EINVAL;
 
-	regmap_write(chip->regmap, AW2013_RSTR, AW2013_RSTR_RESET);
-
 	for_each_available_child_of_node_scoped(np, child) {
 		struct led_init_data init_data = {};
 		u32 source;
@@ -305,19 +303,29 @@ static int aw2013_probe_dt(struct aw2013 *chip)
 		led->cdev.brightness_set_blocking = aw2013_brightness_set;
 		led->cdev.blink_set = aw2013_blink_set;
 
+		mutex_lock(&chip->mutex);
+		chip->num_leds = ++i;
+		if (chip->enabled) {
+			ret = regmap_update_bits(chip->regmap,
+						 AW2013_LCFG(led->num),
+						 AW2013_LCFG_IMAX_MASK,
+						 led->imax);
+			if (ret) {
+				mutex_unlock(&chip->mutex);
+				return ret;
+			}
+		}
+		mutex_unlock(&chip->mutex);
+
 		ret = devm_led_classdev_register_ext(&chip->client->dev,
 						     &led->cdev, &init_data);
 		if (ret < 0)
 			return ret;
-
-		i++;
 	}
 
 	if (!count)
 		return -EINVAL;
 
-	chip->num_leds = i;
-
 	return 0;
 }
 
@@ -393,25 +401,27 @@ static int aw2013_probe(struct i2c_client *client)
 		goto error_reg;
 	}
 
+	ret = regmap_write(chip->regmap, AW2013_RSTR, AW2013_RSTR_RESET);
+	if (ret) {
+		dev_err(&client->dev, "Failed to reset chip: %d\n", ret);
+		goto error_reg;
+	}
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators),
+				     chip->regulators);
+	if (ret) {
+		dev_err(&client->dev,
+			"Failed to disable regulators: %d\n", ret);
+		goto error;
+	}
+
+	mutex_unlock(&chip->mutex);
+
 	ret = devm_add_action(&client->dev, aw2013_chip_disable_action, chip);
 	if (ret)
-		goto error_reg;
+		return ret;
 
-	ret = aw2013_probe_dt(chip);
-	if (ret < 0)
-		goto error_reg;
-
-	ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators),
-				     chip->regulators);
-	if (ret) {
-		dev_err(&client->dev,
-			"Failed to disable regulators: %d\n", ret);
-		goto error;
-	}
-
-	mutex_unlock(&chip->mutex);
-
-	return 0;
+	return aw2013_probe_dt(chip);
 
 error_reg:
 	regulator_bulk_disable(ARRAY_SIZE(chip->regulators),
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 19/21] leds: is31fl32xx: Clamp channel current limit in is31fl3293_reset()
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (16 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 18/21] leds: aw2013: Unlock chip mutex before registering LEDs Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 20/21] leds: flash: Terminate sysfs_groups array with NULL Lee Jones
  2026-10-21 12:32 ` [PATCH 21/21] leds: lm3692x: Use devm_mutex_init() to avoid premature mutex destruction Lee Jones
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Daniel Mack, David Rivshin, linux-leds,
	linux-kernel
  Cc: stable

is31fl3293_reset() uses max() instead of min() when comparing
led_data->max_microamp against IS31FL3293_MAX_MICROAMP, ignoring any
lower led-max-microamp limit configured in the Device Tree and
overflowing the 8-bit current level register if a larger value is
provided.

Clamp led_data->max_microamp to IS31FL3293_MAX_MICROAMP when specified,
falling back to IS31FL3293_MAX_MICROAMP when the optional property is
omitted.

Fixes: a18983b95a61 ("leds: is31f132xx: Add support for is31fl3293")
Closes: https://sashiko.dev/#/bug/linux-878f32ad-ca35-4759-a194-76fe03caee21
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/leds-is31fl32xx.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c
index 285085d27453..aebedf8b2f4b 100644
--- a/drivers/leds/leds-is31fl32xx.c
+++ b/drivers/leds/leds-is31fl32xx.c
@@ -194,7 +194,8 @@ static int is31fl3293_reset(struct is31fl32xx_priv *priv)
 	for (i = 0; i < priv->num_leds; i++) {
 		struct is31fl32xx_led_data *led_data = &priv->leds[i];
 		int current_level_reg = IS31FL3293_CL_REG + led_data->channel - 1;
-		int microamp = max(led_data->max_microamp, IS31FL3293_MAX_MICROAMP);
+		u32 microamp = min_not_zero(led_data->max_microamp,
+					    IS31FL3293_MAX_MICROAMP);
 		int current_level = (microamp * 0xff) / IS31FL3293_MAX_MICROAMP;
 
 		ret = is31fl32xx_write(priv, current_level_reg, current_level);
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 20/21] leds: flash: Terminate sysfs_groups array with NULL
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (17 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 19/21] leds: is31fl32xx: Clamp channel current limit in is31fl3293_reset() Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  2026-10-21 12:32 ` [PATCH 21/21] leds: lm3692x: Use devm_mutex_init() to avoid premature mutex destruction Lee Jones
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Dmitry Antipov, Jacek Anaszewski, Bryan Wu,
	Kyungmin Park, linux-leds, linux-kernel
  Cc: stable

led_flash_init_sysfs_groups() populates fled_cdev->sysfs_groups and
assigns it to led_cdev->groups without writing a trailing NULL entry.
If fled_cdev is not zero-initialised by the caller or is re-registered
with fewer operations, device_add_groups() will read past the populated
entries.

Explicitly NULL-terminate flash_groups at num_sysfs_groups.

Fixes: 7aea8389a77a ("leds: Add LED Flash class extension to the LED subsystem")
Closes: https://sashiko.dev/#/bug/linux-ad7bad43-ab12-40c5-addd-7d1f23d83391
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/led-class-flash.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
index 16b3b6b9365b..90ae93f16193 100644
--- a/drivers/leds/led-class-flash.c
+++ b/drivers/leds/led-class-flash.c
@@ -273,6 +273,8 @@ static void led_flash_init_sysfs_groups(struct led_classdev_flash *fled_cdev)
 	if (ops->fault_get)
 		flash_groups[num_sysfs_groups++] = &led_flash_fault_group;
 
+	flash_groups[num_sysfs_groups] = NULL;
+
 	led_cdev->groups = flash_groups;
 }
 
-- 
2.56.0.218.g1ec904b173-goog


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

* [PATCH 21/21] leds: lm3692x: Use devm_mutex_init() to avoid premature mutex destruction
       [not found] <20261021123406.3163547-1-lee@kernel.org>
                   ` (18 preceding siblings ...)
  2026-10-21 12:32 ` [PATCH 20/21] leds: flash: Terminate sysfs_groups array with NULL Lee Jones
@ 2026-10-21 12:32 ` Lee Jones
  19 siblings, 0 replies; 26+ messages in thread
From: Lee Jones @ 2026-10-21 12:32 UTC (permalink / raw)
  To: lee, Pavel Machek, Dan Murphy, Jacek Anaszewski, linux-leds,
	linux-kernel
  Cc: stable

lm3692x_probe() registers the LED class device using
devm_led_classdev_register_ext(), so the LED is unregistered during
devres release after lm3692x_remove() returns.  Calling mutex_destroy()
in lm3692x_remove() destroys led->lock while the LED sysfs interface is
still active and before devres unregistration turns off the LED via
lm3692x_brightness_set().

Initialise led->lock with devm_mutex_init() before registering the LED
class device and drop mutex_destroy() from lm3692x_remove() so the mutex
outlives the LED device.

Fixes: 9699cb6bbef2 ("leds: lm3692x: Introduce LM3692x dual string driver")
Closes: https://sashiko.dev/#/bug/linux-012e3698-2af6-4390-88c9-d8989d2dc2a6
Cc: stable@vger.kernel.org
Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/leds/leds-lm3692x.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/leds/leds-lm3692x.c b/drivers/leds/leds-lm3692x.c
index 9c58d54c5783..ec53f9d25654 100644
--- a/drivers/leds/leds-lm3692x.c
+++ b/drivers/leds/leds-lm3692x.c
@@ -470,7 +470,10 @@ static int lm3692x_probe(struct i2c_client *client)
 	if (!led)
 		return -ENOMEM;
 
-	mutex_init(&led->lock);
+	ret = devm_mutex_init(&client->dev, &led->lock);
+	if (ret)
+		return ret;
+
 	led->client = client;
 	led->led_dev.brightness_set_blocking = lm3692x_brightness_set;
 	led->model_id = id->driver_data;
@@ -500,7 +503,6 @@ static void lm3692x_remove(struct i2c_client *client)
 	struct lm3692x_led *led = i2c_get_clientdata(client);
 
 	lm3692x_leds_disable(led);
-	mutex_destroy(&led->lock);
 }
 
 static const struct i2c_device_id lm3692x_id[] = {
-- 
2.56.0.218.g1ec904b173-goog


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

* Re: [PATCH 14/21] leds: flash: Avoid divide-by-zero in led_clamp_align()
  2026-10-21 12:32 ` [PATCH 14/21] leds: flash: Avoid divide-by-zero in led_clamp_align() Lee Jones
@ 2026-10-22 19:20   ` Jacek Anaszewski
  2026-10-22 21:00   ` David Laight
  1 sibling, 0 replies; 26+ messages in thread
From: Jacek Anaszewski @ 2026-10-22 19:20 UTC (permalink / raw)
  To: Lee Jones, Pavel Machek, Dmitry Antipov, Jacek Anaszewski,
	Bryan Wu, Kyungmin Park, linux-leds, linux-kernel
  Cc: stable

Hi Lee,

On 10/21/26 2:32 PM, Lee Jones wrote:
> If a flash LED driver leaves a setting's step size as zero, writing to
> the corresponding sysfs attribute invokes led_clamp_align() and triggers
> an integer division by zero when aligning the offset to s->step.
> 
> Clamp s->val to [s->min, s->max] and return early when s->step is zero.
> 
> Fixes: 7aea8389a77a ("leds: Add LED Flash class extension to the LED subsystem")
> Closes: https://sashiko.dev/#/bug/linux-9d06d7fe-310b-4aee-8b16-0fb49550c287
> Cc: stable@vger.kernel.org
> Signed-off-by: Lee Jones <lee@kernel.org>
> ---
>   drivers/leds/led-class-flash.c | 5 +++++
>   1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
> index 181dfd49c6ad..16b3b6b9365b 100644
> --- a/drivers/leds/led-class-flash.c
> +++ b/drivers/leds/led-class-flash.c
> @@ -375,6 +375,11 @@ static void led_clamp_align(struct led_flash_setting *s)
>   {
>   	u32 v, offset;
>   
> +	if (!s->step) {
> +		s->val = clamp(s->val, s->min, s->max);
> +		return;
> +	}
> +
>   	v = s->val + s->step / 2;
>   	v = clamp(v, s->min, s->max);
>   	offset = v - s->min;


Reviewed-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>

-- 
Best regards,
Jacek Anaszewski


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

* Re: [PATCH 14/21] leds: flash: Avoid divide-by-zero in led_clamp_align()
  2026-10-21 12:32 ` [PATCH 14/21] leds: flash: Avoid divide-by-zero in led_clamp_align() Lee Jones
  2026-10-22 19:20   ` Jacek Anaszewski
@ 2026-10-22 21:00   ` David Laight
  2026-10-26 17:31     ` Lee Jones
  1 sibling, 1 reply; 26+ messages in thread
From: David Laight @ 2026-10-22 21:00 UTC (permalink / raw)
  To: Lee Jones
  Cc: Pavel Machek, Dmitry Antipov, Jacek Anaszewski, Bryan Wu,
	Kyungmin Park, linux-leds, linux-kernel, stable

On Wed, 21 Oct 2026 12:32:23 +0000
Lee Jones <lee@kernel.org> wrote:

> If a flash LED driver leaves a setting's step size as zero, writing to
> the corresponding sysfs attribute invokes led_clamp_align() and triggers
> an integer division by zero when aligning the offset to s->step.
> 
> Clamp s->val to [s->min, s->max] and return early when s->step is zero.
> 
> Fixes: 7aea8389a77a ("leds: Add LED Flash class extension to the LED subsystem")
> Closes: https://sashiko.dev/#/bug/linux-9d06d7fe-310b-4aee-8b16-0fb49550c287
> Cc: stable@vger.kernel.org
> Signed-off-by: Lee Jones <lee@kernel.org>
> ---
>  drivers/leds/led-class-flash.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
> index 181dfd49c6ad..16b3b6b9365b 100644
> --- a/drivers/leds/led-class-flash.c
> +++ b/drivers/leds/led-class-flash.c
> @@ -375,6 +375,11 @@ static void led_clamp_align(struct led_flash_setting *s)
>  {
>  	u32 v, offset;
>  
> +	if (!s->step) {
> +		s->val = clamp(s->val, s->min, s->max);
> +		return;
> +	}

Why not just:
	u32 step = s->step ?: 1;
and then use step instead of s->step.

David

> +
>  	v = s->val + s->step / 2;
>  	v = clamp(v, s->min, s->max);
>  	offset = v - s->min;


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

* Re: [PATCH 14/21] leds: flash: Avoid divide-by-zero in led_clamp_align()
  2026-10-22 21:00   ` David Laight
@ 2026-10-26 17:31     ` Lee Jones
  2026-10-26 18:37       ` David Laight
  0 siblings, 1 reply; 26+ messages in thread
From: Lee Jones @ 2026-10-26 17:31 UTC (permalink / raw)
  To: David Laight
  Cc: Pavel Machek, Dmitry Antipov, Jacek Anaszewski, Bryan Wu,
	Kyungmin Park, linux-leds, linux-kernel, stable

On Thu, 22 Oct 2026, David Laight wrote:

> On Wed, 21 Oct 2026 12:32:23 +0000
> Lee Jones <lee@kernel.org> wrote:
> 
> > If a flash LED driver leaves a setting's step size as zero, writing to
> > the corresponding sysfs attribute invokes led_clamp_align() and triggers
> > an integer division by zero when aligning the offset to s->step.
> > 
> > Clamp s->val to [s->min, s->max] and return early when s->step is zero.
> > 
> > Fixes: 7aea8389a77a ("leds: Add LED Flash class extension to the LED subsystem")
> > Closes: https://sashiko.dev/#/bug/linux-9d06d7fe-310b-4aee-8b16-0fb49550c287
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Lee Jones <lee@kernel.org>
> > ---
> >  drivers/leds/led-class-flash.c | 5 +++++
> >  1 file changed, 5 insertions(+)
> > 
> > diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
> > index 181dfd49c6ad..16b3b6b9365b 100644
> > --- a/drivers/leds/led-class-flash.c
> > +++ b/drivers/leds/led-class-flash.c
> > @@ -375,6 +375,11 @@ static void led_clamp_align(struct led_flash_setting *s)
> >  {
> >  	u32 v, offset;
> >  
> > +	if (!s->step) {
> > +		s->val = clamp(s->val, s->min, s->max);
> > +		return;
> > +	}
> 
> Why not just:
> 	u32 step = s->step ?: 1;
> and then use step instead of s->step.

I can see where you're coming from, but I don't think this is better.

With `step = 1`, the reader has to mentally trace `1 / 2 == 0` and `1 *
(offset / 1) == offset` to see that it reduces to a plain clamp and the
CPU still executes a redundant integer division.

IMHO, simple, easy-to-read, maintainable code wins out over clever code.

> > +
> >  	v = s->val + s->step / 2;
> >  	v = clamp(v, s->min, s->max);
> >  	offset = v - s->min;
> 

-- 
Lee Jones

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

* Re: [PATCH 14/21] leds: flash: Avoid divide-by-zero in led_clamp_align()
  2026-10-26 17:31     ` Lee Jones
@ 2026-10-26 18:37       ` David Laight
  0 siblings, 0 replies; 26+ messages in thread
From: David Laight @ 2026-10-26 18:37 UTC (permalink / raw)
  To: Lee Jones
  Cc: Pavel Machek, Dmitry Antipov, Jacek Anaszewski, Bryan Wu,
	Kyungmin Park, linux-leds, linux-kernel, stable

On Mon, 26 Oct 2026 17:31:29 +0000
Lee Jones <lee@kernel.org> wrote:

> On Thu, 22 Oct 2026, David Laight wrote:
> 
> > On Wed, 21 Oct 2026 12:32:23 +0000
> > Lee Jones <lee@kernel.org> wrote:
> >   
> > > If a flash LED driver leaves a setting's step size as zero, writing to
> > > the corresponding sysfs attribute invokes led_clamp_align() and triggers
> > > an integer division by zero when aligning the offset to s->step.
> > > 
> > > Clamp s->val to [s->min, s->max] and return early when s->step is zero.
> > > 
> > > Fixes: 7aea8389a77a ("leds: Add LED Flash class extension to the LED subsystem")
> > > Closes: https://sashiko.dev/#/bug/linux-9d06d7fe-310b-4aee-8b16-0fb49550c287
> > > Cc: stable@vger.kernel.org
> > > Signed-off-by: Lee Jones <lee@kernel.org>
> > > ---
> > >  drivers/leds/led-class-flash.c | 5 +++++
> > >  1 file changed, 5 insertions(+)
> > > 
> > > diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
> > > index 181dfd49c6ad..16b3b6b9365b 100644
> > > --- a/drivers/leds/led-class-flash.c
> > > +++ b/drivers/leds/led-class-flash.c
> > > @@ -375,6 +375,11 @@ static void led_clamp_align(struct led_flash_setting *s)
> > >  {
> > >  	u32 v, offset;
> > >  
> > > +	if (!s->step) {
> > > +		s->val = clamp(s->val, s->min, s->max);
> > > +		return;
> > > +	}  
> > 
> > Why not just:
> > 	u32 step = s->step ?: 1;
> > and then use step instead of s->step.  
> 
> I can see where you're coming from, but I don't think this is better.
> 
> With `step = 1`, the reader has to mentally trace `1 / 2 == 0` and `1 *
> (offset / 1) == offset` to see that it reduces to a plain clamp and the
> CPU still executes a redundant integer division.

That happens with a step of one anyway.
All my suggestion does is treat the unexpected 0 as being the same as 1
instead of optimising for it being zero.

David

> 
> IMHO, simple, easy-to-read, maintainable code wins out over clever code.
> 
> > > +
> > >  	v = s->val + s->step / 2;
> > >  	v = clamp(v, s->min, s->max);
> > >  	offset = v - s->min;  
> >   
> 


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

* Re: [PATCH 04/21] leds: aw2013: Guard LED array index in aw2013_probe_dt()
  2026-10-21 12:32 ` [PATCH 04/21] leds: aw2013: Guard LED array index in aw2013_probe_dt() Lee Jones
@ 2026-10-27 14:27   ` Nikita Travkin
  0 siblings, 0 replies; 26+ messages in thread
From: Nikita Travkin @ 2026-10-27 14:27 UTC (permalink / raw)
  To: Lee Jones; +Cc: Pavel Machek, Nikita Travkin, linux-leds, linux-kernel, stable

Lee Jones писал(а) 21.10.2026 17:32:
> aw2013_probe_dt() validates the initial child node count against
> AW2013_MAX_LEDS via of_get_available_child_count() before iterating over
> available child nodes with for_each_available_child_of_node_scoped().
> 
> Add an explicit bounds check on the loop index before indexing into
> chip->leds[] to ensure the statically sized array cannot be overrun if
> additional child nodes become available during iteration.
> 
> Fixes: 59ea3c9faf32 ("leds: add aw2013 driver")
> Closes: https://sashiko.dev/#/bug/linux-577a1fa0-4e80-42cc-8c7f-34c43c131d95
> Cc: stable@vger.kernel.org
> Signed-off-by: Lee Jones <lee@kernel.org>

Reviewed-by: Nikita Travkin <nikita@trvn.ru>

> ---
>  drivers/leds/leds-aw2013.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c
> index 216755d6010f..dfeac8b2993f 100644
> --- a/drivers/leds/leds-aw2013.c
> +++ b/drivers/leds/leds-aw2013.c
> @@ -286,6 +286,9 @@ static int aw2013_probe_dt(struct aw2013 *chip)
>  			continue;
>  		}
>  
> +		if (i >= AW2013_MAX_LEDS)
> +			return -EINVAL;
> +
>  		led = &chip->leds[i];
>  		led->num = source;
>  		led->chip = chip;

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

* Re: [PATCH 18/21] leds: aw2013: Unlock chip mutex before registering LEDs
  2026-10-21 12:32 ` [PATCH 18/21] leds: aw2013: Unlock chip mutex before registering LEDs Lee Jones
@ 2026-10-27 14:28   ` Nikita Travkin
  0 siblings, 0 replies; 26+ messages in thread
From: Nikita Travkin @ 2026-10-27 14:28 UTC (permalink / raw)
  To: Lee Jones; +Cc: Pavel Machek, Nikita Travkin, linux-leds, linux-kernel, stable

Lee Jones писал(а) 21.10.2026 17:32:
> aw2013_probe() holds chip->mutex across aw2013_probe_dt(), which calls
> devm_led_classdev_register_ext().  When a default trigger such as
> "timer" is configured on an LED in the Device Tree, the LED core
> synchronously activates the trigger during registration and invokes
> aw2013_blink_set() on the same thread, which attempts to acquire
> chip->mutex and deadlocks.
> 
> Reset the chip, disable the regulators, and release chip->mutex in
> aw2013_probe() before calling aw2013_probe_dt(), and update
> chip->num_leds before each LED is registered so trigger callbacks can
> enable the chip cleanly during registration.
> 
> Fixes: 59ea3c9faf32 ("leds: add aw2013 driver")
> Closes: https://sashiko.dev/#/bug/linux-5e2c9083-b95b-4aa4-aa0a-b0be8865ff12
> Cc: stable@vger.kernel.org
> Signed-off-by: Lee Jones <lee@kernel.org>

Reviewed-by: Nikita Travkin <nikita@trvn.ru>

Thanks for making those fixes!
Nikita

> ---
>  drivers/leds/leds-aw2013.c | 54 ++++++++++++++++++++++----------------
>  1 file changed, 32 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c
> index dfeac8b2993f..c947cd068963 100644
> --- a/drivers/leds/leds-aw2013.c
> +++ b/drivers/leds/leds-aw2013.c
> @@ -271,8 +271,6 @@ static int aw2013_probe_dt(struct aw2013 *chip)
>  	if (!count || count > AW2013_MAX_LEDS)
>  		return -EINVAL;
>  
> -	regmap_write(chip->regmap, AW2013_RSTR, AW2013_RSTR_RESET);
> -
>  	for_each_available_child_of_node_scoped(np, child) {
>  		struct led_init_data init_data = {};
>  		u32 source;
> @@ -305,19 +303,29 @@ static int aw2013_probe_dt(struct aw2013 *chip)
>  		led->cdev.brightness_set_blocking = aw2013_brightness_set;
>  		led->cdev.blink_set = aw2013_blink_set;
>  
> +		mutex_lock(&chip->mutex);
> +		chip->num_leds = ++i;
> +		if (chip->enabled) {
> +			ret = regmap_update_bits(chip->regmap,
> +						 AW2013_LCFG(led->num),
> +						 AW2013_LCFG_IMAX_MASK,
> +						 led->imax);
> +			if (ret) {
> +				mutex_unlock(&chip->mutex);
> +				return ret;
> +			}
> +		}
> +		mutex_unlock(&chip->mutex);
> +
>  		ret = devm_led_classdev_register_ext(&chip->client->dev,
>  						     &led->cdev, &init_data);
>  		if (ret < 0)
>  			return ret;
> -
> -		i++;
>  	}
>  
>  	if (!count)
>  		return -EINVAL;
>  
> -	chip->num_leds = i;
> -
>  	return 0;
>  }
>  
> @@ -393,25 +401,27 @@ static int aw2013_probe(struct i2c_client *client)
>  		goto error_reg;
>  	}
>  
> +	ret = regmap_write(chip->regmap, AW2013_RSTR, AW2013_RSTR_RESET);
> +	if (ret) {
> +		dev_err(&client->dev, "Failed to reset chip: %d\n", ret);
> +		goto error_reg;
> +	}
> +
> +	ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators),
> +				     chip->regulators);
> +	if (ret) {
> +		dev_err(&client->dev,
> +			"Failed to disable regulators: %d\n", ret);
> +		goto error;
> +	}
> +
> +	mutex_unlock(&chip->mutex);
> +
>  	ret = devm_add_action(&client->dev, aw2013_chip_disable_action, chip);
>  	if (ret)
> -		goto error_reg;
> +		return ret;
>  
> -	ret = aw2013_probe_dt(chip);
> -	if (ret < 0)
> -		goto error_reg;
> -
> -	ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators),
> -				     chip->regulators);
> -	if (ret) {
> -		dev_err(&client->dev,
> -			"Failed to disable regulators: %d\n", ret);
> -		goto error;
> -	}
> -
> -	mutex_unlock(&chip->mutex);
> -
> -	return 0;
> +	return aw2013_probe_dt(chip);
>  
>  error_reg:
>  	regulator_bulk_disable(ARRAY_SIZE(chip->regulators),

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

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

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20261021123406.3163547-1-lee@kernel.org>
2026-10-21 12:32 ` [PATCH 01/21] leds: lm3532: Propagate error from devm_regulator_get() Lee Jones
2026-10-21 12:32 ` [PATCH 03/21] leds: trigger: netdev: Hold RTNL lock across hw_control_get_device() in activate Lee Jones
2026-10-21 12:32 ` [PATCH 04/21] leds: aw2013: Guard LED array index in aw2013_probe_dt() Lee Jones
2026-10-27 14:27   ` Nikita Travkin
2026-10-21 12:32 ` [PATCH 05/21] leds: pca955x: Take a reference on the child firmware node Lee Jones
2026-10-21 12:32 ` [PATCH 06/21] leds: lp50xx: Guard sub-LED count in lp50xx_probe_dt() Lee Jones
2026-10-21 12:32 ` [PATCH 07/21] leds: trigger: netdev: Serialise work cancellation and state updates Lee Jones
2026-10-21 12:32 ` [PATCH 08/21] leds: sgm3140: Replace powerdown timer with delayed work Lee Jones
2026-10-21 12:32 ` [PATCH 09/21] leds: sgm3140: Cancel powerdown work via devres after LED unregistration Lee Jones
2026-10-21 12:32 ` [PATCH 10/21] leds: class: Initialise trigger_lock before exposing sysfs attributes Lee Jones
2026-10-21 12:32 ` [PATCH 11/21] leds: class: Unlock led_access before unregistering device on error Lee Jones
2026-10-21 12:32 ` [PATCH 12/21] leds: aat1290: Retain child device_node reference for device lifetime Lee Jones
2026-10-21 12:32 ` [PATCH 13/21] leds: aat1290: Prevent out-of-bounds read in aat1290_brightness_to_intensity() Lee Jones
2026-10-21 12:32 ` [PATCH 14/21] leds: flash: Avoid divide-by-zero in led_clamp_align() Lee Jones
2026-10-22 19:20   ` Jacek Anaszewski
2026-10-22 21:00   ` David Laight
2026-10-26 17:31     ` Lee Jones
2026-10-26 18:37       ` David Laight
2026-10-21 12:32 ` [PATCH 15/21] leds: lm3532: Validate LED string indices in lm3532_parse_node() Lee Jones
2026-10-21 12:32 ` [PATCH 16/21] leds: lm3532: Clamp full-scale current to minimum bound Lee Jones
2026-10-21 12:32 ` [PATCH 17/21] leds: aat1290: Avoid leaking devres pinctrl handles on strobe source changes Lee Jones
2026-10-21 12:32 ` [PATCH 18/21] leds: aw2013: Unlock chip mutex before registering LEDs Lee Jones
2026-10-27 14:28   ` Nikita Travkin
2026-10-21 12:32 ` [PATCH 19/21] leds: is31fl32xx: Clamp channel current limit in is31fl3293_reset() Lee Jones
2026-10-21 12:32 ` [PATCH 20/21] leds: flash: Terminate sysfs_groups array with NULL Lee Jones
2026-10-21 12:32 ` [PATCH 21/21] leds: lm3692x: Use devm_mutex_init() to avoid premature mutex destruction Lee Jones

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