All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Armin Wolf" <W_Armin@gmx.de>
Cc: linux-leds@vger.kernel.org, lee@kernel.org
Subject: Re: [PATCH 09/10] leds: Support custom sysfs groups on multicolor and flash LEDs
Date: Sun, 18 Oct 2026 14:09:26 +0000	[thread overview]
Message-ID: <sashiko-outbox-176184@kernel.org> (raw)
In-Reply-To: <20261018135339.1109271-10-W_Armin@gmx.de>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] leds: dangling led_cdev->dev pointer on registration failure causes UAF
--

commit fc841d87d7344c0d4e24b361394ed5d20afd7ffb
Author: Armin Wolf <W_Armin@gmx.de>

leds: Support custom sysfs groups on multicolor and flash LEDs

This commit moves the multicolor and flash LED sysfs attribute groups onto
dedicated device types ("multicolor", "flash", and "standard") so that drivers
can populate led_cdev->groups without having them overwritten during
registration.

> diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
> index 953265fddb7d9..e023511cea1c1 100644
> --- a/drivers/leds/led-class-flash.c
> +++ b/drivers/leds/led-class-flash.c

[ ... ]

> @@ -289,26 +282,29 @@ int led_classdev_flash_register_ext(struct device *parent,
>  
>  	led_cdev = &fled_cdev->led_cdev;
>  
> -	if (led_cdev->flags & LED_DEV_CAP_FLASH) {
> -		if (!led_cdev->brightness_set_blocking)
> -			return -EINVAL;
> +	if (!(led_cdev->flags & LED_DEV_CAP_FLASH))
> +		return led_classdev_register_ext(parent, led_cdev, init_data);
>  
> -		ops = fled_cdev->ops;
> -		if (!ops || !ops->strobe_set)
> -			return -EINVAL;
> +	if (!led_cdev->brightness_set_blocking)
> +		return -EINVAL;
>  
> -		led_cdev->flash_resume = led_flash_resume;
> +	ops = fled_cdev->ops;
> +	if (!ops || !ops->strobe_set)
> +		return -EINVAL;
>  
> -		/* Select the sysfs attributes to be created for the device */
> -		led_flash_init_sysfs_groups(fled_cdev);
> -	}
> +	led_cdev->flash_resume = led_flash_resume;
>  
>  	/* Register led class device */
> -	ret = led_classdev_register_ext(parent, led_cdev, init_data);
> +	ret = led_classdev_init(parent, led_cdev, init_data);
>  	if (ret < 0)
>  		return ret;
>  
> -	return 0;
> +	led_cdev->dev->type = &led_flash_device_type;
> +	ret = led_classdev_add(led_cdev);
> +	if (ret < 0)
> +		put_device(led_cdev->dev);
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL_GPL(led_classdev_flash_register_ext);
>  
> diff --git a/drivers/leds/led-class-multicolor.c b/drivers/leds/led-class-multicolor.c
> index 57df0b2e785b5..9b8c37f7bdf45 100644
> --- a/drivers/leds/led-class-multicolor.c
> +++ b/drivers/leds/led-class-multicolor.c

[ ... ]

> @@ -176,9 +183,16 @@ int led_classdev_multicolor_register_ext(struct device *parent,
>  
>  	led_cdev = &mcled_cdev->led_cdev;
>  	led_cdev->flags |= LED_MULTI_COLOR;
> -	mcled_cdev->led_cdev.groups = led_multicolor_groups;
> +	ret = led_classdev_init(parent, led_cdev, init_data);
> +	if (ret < 0)
> +		return ret;
> +
> +	led_cdev->dev->type = &led_multicolor_device_type;
> +	ret = led_classdev_add(led_cdev);
> +	if (ret < 0)
> +		put_device(led_cdev->dev);
>  
> -	return led_classdev_register_ext(parent, led_cdev, init_data);
> +	return ret;
>  }
>  EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext);

[Severity: High]
Could this leave led_cdev->dev as a dangling pointer when registration fails,
leading to a use-after-free in led_classdev_unregister()?

In led_classdev_init(), led_cdev->dev is allocated and initialized via
device_initialize():

drivers/leds/led-class.c:led_classdev_init() {
	...
	led_cdev->dev = kzalloc_obj(*led_cdev->dev);
	if (!led_cdev->dev)
		return -ENOMEM;

	device_initialize(led_cdev->dev);
	...
	ret = kobject_set_name(&led_cdev->dev->kobj, "%s", final_name);
	if (ret < 0)
	{
		put_device(led_cdev->dev);
		return ret;
	}
	...
}

If kobject_set_name() fails in led_classdev_init(), or if led_classdev_add()
subsequently fails (for example when device_add() fails due to a sysfs group
conflict or -ENOMEM) in led_classdev_flash_register_ext(),
led_classdev_multicolor_register_ext(), or led_classdev_register_ext(),
put_device(led_cdev->dev) releases the final reference and frees the struct
device via led_classdev_release(), but led_cdev->dev is not reset to NULL and
led_cdev->node is never added to leds_list.

Since commit 1dbb9fb4082ce2 ("leds: Allow to call led_classdev_unregister()
unconditionally"), led_classdev_unregister() permits unconditional teardown by
checking:

drivers/leds/led-class.c:led_classdev_unregister() {
	if (IS_ERR_OR_NULL(led_cdev->dev))
		return;
	...
	device_unregister(led_cdev->dev);
	...
	down_write(&leds_list_lock);
	list_del(&led_cdev->node);
	up_write(&leds_list_lock);
	...
}

Several drivers rely on this contract when cleaning up after failed
registration or on driver removal, such as drivers/leds/leds-blinkm.c:

drivers/leds/leds-blinkm.c:register_multicolor() {
	...
	err = led_classdev_multicolor_register(&client->dev, &mc_led->cdev.mcled_cdev);
	if (err < 0) {
		dev_err(&client->dev, "couldn't register LED %s\n",
				mc_led->cdev.led_cdev.name);
		sysfs_remove_group(&client->dev.kobj, &blinkm_group);
	}
	return 0;
}

as well as drivers/platform/x86/asus-wmi.c (where asus_wmi_led_init() jumps to
asus_wmi_led_exit() on error), drivers/platform/x86/asus-laptop.c, and
drivers/platform/x86/toshiba_acpi.c.

Because led_cdev->dev still holds a non-NULL, non-ERR_PTR address after
put_device(led_cdev->dev), wouldn't a subsequent call to
led_classdev_unregister() (or its flash and multicolor wrappers) bypass the
IS_ERR_OR_NULL(led_cdev->dev) check, pass the freed pointer to
device_unregister(led_cdev->dev), and dereference NULL in
list_del(&led_cdev->node)?

Should led_cdev->dev be set to NULL after put_device(led_cdev->dev) in the
error paths of led_classdev_init(), led_classdev_register_ext(),
led_classdev_flash_register_ext(), and led_classdev_multicolor_register_ext()?

> diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
> index ace417a2388e0..49b321b3d863b 100644
> --- a/drivers/leds/led-class.c
> +++ b/drivers/leds/led-class.c
> @@ -613,6 +613,10 @@ int led_classdev_add(struct led_classdev *led_cdev)
>  }
>  EXPORT_SYMBOL_GPL(led_classdev_add);
>  
> +static const struct device_type led_device_type = {
> +	.name = "standard",
> +};
> +
>  /**
>   * led_classdev_register_ext - register a new object of led_classdev class
>   *                             with init data.
> @@ -631,6 +635,7 @@ int led_classdev_register_ext(struct device *parent,
>  	if (ret < 0)
>  		return ret;
>  
> +	led_cdev->dev->type = &led_device_type;
>  	ret = led_classdev_add(led_cdev);
>  	if (ret < 0)
>  		put_device(led_cdev->dev);

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261018135339.1109271-1-W_Armin@gmx.de?part=9

  reply	other threads:[~2026-10-18 14:09 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-18 13:46 [PATCH 00/10] leds: class: Support custom sysfs groups on multicolor and flash LEDs Armin Wolf
2026-10-18 13:46 ` [PATCH 01/10] leds: class: Constify sysfs attributes Armin Wolf
2026-10-18 13:57   ` sashiko-bot
2026-10-18 13:46 ` [PATCH 02/10] leds: multicolor: " Armin Wolf
2026-10-18 13:57   ` sashiko-bot
2026-10-18 13:46 ` [PATCH 03/10] leds: flash: " Armin Wolf
2026-10-18 13:56   ` sashiko-bot
2026-10-18 13:46 ` [PATCH 04/10] leds: class: Create "brightness_hw_changed" attribute atomically Armin Wolf
2026-10-18 14:11   ` sashiko-bot
2026-10-18 13:46 ` [PATCH 05/10] leds: class: Fix race condition when creating the device Armin Wolf
2026-10-18 13:58   ` sashiko-bot
2026-10-18 13:46 ` [PATCH 06/10] leds: class: Take the LED access lock when reading brightness_hw_changed Armin Wolf
2026-10-18 14:03   ` sashiko-bot
2026-10-18 17:08     ` Armin Wolf
2026-10-18 13:46 ` [PATCH 07/10] leds: class: Use correct type for brightness_hw_changed field Armin Wolf
2026-10-18 14:11   ` sashiko-bot
2026-10-18 13:46 ` [PATCH 08/10] leds: class: Split led_classdev_register_ext() Armin Wolf
2026-10-18 14:15   ` sashiko-bot
2026-10-18 17:14     ` Armin Wolf
2026-10-18 13:46 ` [PATCH 09/10] leds: Support custom sysfs groups on multicolor and flash LEDs Armin Wolf
2026-10-18 14:09   ` sashiko-bot [this message]
2026-10-18 13:46 ` [PATCH 10/10] leds: multicolor: Adjust maximum subled intensity during initialization Armin Wolf
2026-10-18 13:58   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-176184@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=W_Armin@gmx.de \
    --cc=lee@kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.