Linux LED subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Markus Probst" <markus.probst@posteo.de>
Cc: ojeda@kernel.org, linux-leds@vger.kernel.org, lee@kernel.org,
	linux-pci@vger.kernel.org
Subject: Re: [PATCH v23 3/3] rust: leds: add multicolor classdev abstractions
Date: Thu, 16 Jul 2026 18:21:39 +0000	[thread overview]
Message-ID: <20260716182139.E2E8E1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260716-rust_leds-v23-3-e91f5b608b56@posteo.de>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Safe methods `brightness()` and `intensity()` in `MultiColorSubLed` perform non-synchronized plain reads of an `UnsafeCell`, causing Undefined Behavior due to data races with concurrent C subsystem modifications.
- [High] Fragile `fwnode` reference management in `DeviceBuilder::build_multicolor` and `MultiColorDevice::drop` causes `ARef<FwNode>` leaks or invalid refcount decrements.
--

--- Patch [3]: [PATCH v23 3/3] rust: leds: add multicolor classdev abstractions ---
commit 6c4e554be24453ed9f19eef4d69cdcd8cacfc0d1
Author: Markus Probst <markus.probst@posteo.de>

rust: leds: add multicolor classdev abstractions

Implement the abstractions needed for multicolor led class devices,
including MultiColor, MultiColorSubLed, MultiColorDevice, and 
DeviceBuilder::build_multicolor to register new class devices.

> diff --git a/rust/kernel/led/multicolor.rs b/rust/kernel/led/multicolor.rs
> new file mode 100644
> index 0000000000000..82fe96fd5273b
> --- /dev/null
> +++ b/rust/kernel/led/multicolor.rs

[ ... ]

> +    /// The intensity of the sub led.
> +    #[inline]
> +    pub const fn intensity(&self) -> u32 {
> +        // SAFETY:
> +        // - self.intensity.get() is a valid pointer to u32.
> +        // - We don't have exclusive or immutable access to self.intensity,
> +        //   but the alignment should prevent "load tearing".
> +        unsafe { *self.intensity.get() }

[Severity: High]
Does this unsynchronized plain load introduce a data race? If a driver calls
this safe method from an interrupt handler or background thread while the C
subsystem concurrently updates the value via sysfs (which holds a C mutex
the Rust side does not take), could this trigger undefined behavior?

> +    }
> +
> +    /// The brightness of the sub led.
> +    #[inline]
> +    pub const fn brightness(&self) -> u32 {
> +        // SAFETY:
> +        // - self.brightness.get() is a valid pointer to u32.
> +        // - We don't have exclusive or immutable access to self.brightness,
> +        //   but the alignment should prevent "load tearing".
> +        unsafe { *self.brightness.get() }

[Severity: High]
Similarly, could reading brightness() here cause undefined behavior due to
concurrent sysfs modifications?

[ ... ]

> +                // SAFETY:
> +                // - parent.as_ref().as_raw() is guaranteed to be a pointer to a valid
> +                //    device.
> +                // - ptr is guaranteed to be a pointer to an initialized led_classdev_mc.
> +                to_result(unsafe {
> +                    bindings::led_classdev_multicolor_register_ext(
> +                        parent.as_ref().as_raw(),
> +                        ptr,
> +                        if self.name.is_none() {
> +                            &raw mut init_data
> +                        } else {
> +                            core::ptr::null_mut()
> +                        },
> +                    )
> +                })?;
> +
> +                subled_guard.dismiss();
> +
> +                core::mem::forget(self.fwnode); // keep the reference count incremented

[Severity: High]
Does this unconditionally leak the fwnode reference when self.name is set?

If self.name is Some, the C registration function is passed a NULL pointer for
init_data, meaning the device fwnode is never set. By calling forget()
unconditionally here, the reference count is incremented but the fwnode is
not stored in the C device, which might permanently leak the reference.

[ ... ]

> +#[pinned_drop]
> +impl<'bound, T: LedOps<Mode = MultiColor> + 'bound> PinnedDrop for MultiColorDevice<'bound, T> {
> +    fn drop(self: Pin<&mut Self>) {
> +        let raw = self.classdev.get();
> +        // SAFETY: The existence of self guarantees that self.classdev.get() is a pointer to a
> +        // valid led_classdev_mc.
> +        let dev: &device::Device = unsafe { device::Device::from_raw((*raw).led_cdev.dev) };
> +
> +        let _fwnode = dev
> +            .fwnode()
> +            // SAFETY: the reference count of fwnode has previously been
> +            // incremented in led::DeviceBuilder::build_multicolor.
> +            .map(|fwnode| unsafe { ARef::from_raw(NonNull::from(fwnode)) });

[Severity: High]
Can this cause a use-after-free or double-free on an unrelated fwnode?

If self.fwnode was None during builder initialization, but the C subsystem
later assigns an unrelated fwnode to the device, it seems this code would
incorrectly wrap it in an ARef and decrement its refcount.

Alternatively, if dev.fwnode() returns None because init_data was NULL earlier,
the previously forgotten fwnode refcount is never decremented, leaking it.
It appears this same pattern may also affect normal device builders.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260716-rust_leds-v23-0-e91f5b608b56@posteo.de?part=3

      reply	other threads:[~2026-07-16 18:21 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-16 17:51 [PATCH v23 0/3] rust: leds: add led classdev abstractions Markus Probst
2026-07-16 17:51 ` [PATCH v23 1/3] rust: leds: add basic " Markus Probst
2026-07-16 18:40   ` sashiko-bot
2026-07-16 17:51 ` [PATCH v23 2/3] rust: leds: add Mode trait Markus Probst
2026-07-16 18:02   ` sashiko-bot
2026-07-16 17:51 ` [PATCH v23 3/3] rust: leds: add multicolor classdev abstractions Markus Probst
2026-07-16 18:21   ` sashiko-bot [this message]

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=20260716182139.E2E8E1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=lee@kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=markus.probst@posteo.de \
    --cc=ojeda@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox