Re: [PATCH v22 1/3] rust: leds: add basic led classdev abstractions

[email protected] Sun, 12 Jul 2026 17:42:32 +0000
Newsgroups org.kernel.vger.linux-leds,org.kernel.vger.linux-pci
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The firmware node reference is insecurely tracked by assuming the C layer's `dev->fwnode` field remains unmodified, which can lead to reference count underflow, use-after-free, or memory leaks.
- [Medium] The LED device is registered using the unmanaged `led_classdev_register_ext()` instead of the managed `devm_led_classdev_register_ext()`, violating subsystem lifecycle guidelines and introducing devres LIFO ordering hazards.
--

--- Patch [1]: [PATCH v22 1/3] rust: leds: add basic led classdev abstractions ---
commit 7eff903565ff4a4fae9e842098053e60f2989206
Author: Markus Probst <[email protected]>

rust: leds: add basic led classdev abstractions

This commit introduces core abstractions for LED class devices in Rust. It
implements traits for handling LED operations, a device builder, and a safe
wrapper for led_classdev.

> diff --git a/rust/kernel/led/normal.rs b/rust/kernel/led/normal.rs
> index 0000000000000..816db7c576894
> --- /dev/null
> +++ b/rust/kernel/led/normal.rs

[ ... ]

> @@ -65,22 +65,22 @@ impl<'init, S: DeviceBuilderState> DeviceBuilder<'init, S> {
>                  // 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`.
>                  to_result(unsafe {
>                      bindings::led_classdev_register_ext(

[Severity: Medium]
Does calling the unmanaged bindings::led_classdev_register_ext() instead of
the managed bindings::devm_led_classdev_register_ext() violate the LED
subsystem lifecycle guidelines?

Relying on manual PinnedDrop for unregistration appears to decouple the
device lifecycle from the C driver core's devres cleanup. Could this
introduce devres teardown ordering hazards, use-after-free, or resource
leaks if user-space sysfs attributes are accessed after device removal?

>                          parent.as_ref().as_raw(),
>                          ptr,
>                          if self.name.is_none() {
>                              &raw mut init_data
>                          } else {
>                              core::ptr::null_mut()
>                          },
>                      )
>                  })?;
>  
>                  core::mem::forget(self.fwnode); // keep the reference count incremented

[Severity: High]
If the driver was built without an fwnode (where self.fwnode is None), but
the C layer assigns a node to dev->fwnode during the device's lifetime, will
dev.fwnode() return Some(fwnode) during unregistration?

It seems this would unconditionally create an ARef from this unowned pointer
and drop it, decrementing a reference count it never acquired.

Similarly, if the C layer replaces a previously provided node, could the
original node leak and the new node be improperly decremented?

>  
>                  Ok::<_, Error>(())
>              }),
>              _p: PhantomData,
>          })
>      }
>  }

[ ... ]

> @@ -211,20 +211,20 @@ impl<T: LedOps> Adapter<T> {
>  #[pinned_drop]
>  impl<'bound, T: LedOps + 'bound> PinnedDrop for Device<'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`.
>          let dev: &device::Device = unsafe { device::Device::from_raw((*raw).dev) };
>  
>          let _fwnode = dev
>              .fwnode()
>              // SAFETY: the reference count of `fwnode` has previously been
>              // incremented in `led::DeviceBuilder::build`.
>              .map(|fwnode| unsafe { ARef::from_raw(NonNull::from(fwnode)) });

[Severity: High]
As mentioned above, if the fwnode was dynamically assigned or replaced by the
C layer, is it safe to unconditionally construct an ARef from the dev->fwnode
pointer here?

>  
>          // SAFETY: The existence of `self` guarantees that `self.classdev` has previously been
>          // successfully registered with `led_classdev_register_ext`.
>          unsafe { bindings::led_classdev_unregister(raw) };

[Severity: Medium]
As asked earlier, could relying on manual unregistration here during Drop
break standard C-level devres lifecycle ordering?

>      }
>  }

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=1