Re: [PATCH RESEND v23 3/3] rust: leds: add multicolor classdev abstractions
[email protected] Wed, 05 Aug 2026 20:52:12 +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 3 potential issue(= s) to consider: - [High] Unsound fwnode reference counting and recovery logic leads to a me= mory leak or use-after-free. - [High] Unsynchronized concurrent reads of `brightness` and `intensity` cr= eate a data race, resulting in Undefined Behavior. - [Low] Commit message description is not capitalized, violating the LED su= bsystem guidelines. -- --- Patch [3]: [PATCH RESEND v23 3/3] rust: leds: add multicolor classdev a= bstractions --- commit 31ed8e2758580675a7a667a24dbbce311465d001 Author: Markus Probst <[email protected]> rust: leds: add multicolor classdev abstractions Implement the abstractions needed for multicolor led class devices, including led::MultiColor, MultiColorSubLed, and led::MultiColorDevice. > rust: leds: add multicolor classdev abstractions [Severity: Low] This isn't a bug, but the commit message description is not capitalized, violating the LED subsystem guidelines. Should this be "Add multicolor classdev abstractions"? > 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.intens= ity`, > + // but the alignment should prevent "load tearing". > + unsafe { *self.intensity.get() } > + } > + > + /// 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.bright= ness`, > + // but the alignment should prevent "load tearing". > + unsafe { *self.brightness.get() } > + } [Severity: High] Does this code introduce undefined behavior due to unsynchronized concurrent reads? The C subsystem updates these fields concurrently when user-space writes to sysfs. In Rust's memory model, plain pointer dereferences on non-atomic variables that can be concurrently mutated constitute a data race and strict undefined behavior. Should this use core::ptr::read_volatile or atomics instead? [ ... ] > + // SAFETY: > + // - `parent.as_ref().as_raw()` is guaranteed to be a po= inter to a valid > + // `device`. > + // - `ptr` is guaranteed to be a pointer to an initializ= ed `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 co= unt incremented > + > + Ok::<_, Error>(()) > + }), [Severity: High] Can this code leak the fwnode reference? If self.name is present, null_mut() is passed for init_data, meaning the fwnode is never passed to the C subsystem. However, core::mem::forget() is called unconditionally, leaking the reference since the device will not have the fwnode for recovery during drop. [ ... ] > +#[pinned_drop] > +impl<'bound, T: LedOps<Mode =3D MultiColor> + 'bound> PinnedDrop for Mul= tiColorDevice<'bound, T> { > + fn drop(self: Pin<&mut Self>) { > + let raw =3D self.classdev.get(); > + // SAFETY: The existence of `self` guarantees that `self.classde= v.get()` is a pointer to a > + // valid `led_classdev_mc`. > + let dev: &device::Device =3D unsafe { device::Device::from_raw((= *raw).led_cdev.dev) }; > + > + let _fwnode =3D dev > + .fwnode() > + // SAFETY: the reference count of `fwnode` has previously be= en > + // incremented in `led::DeviceBuilder::build_multicolor`. > + .map(|fwnode| unsafe { ARef::from_raw(NonNull::from(fwnode))= }); [Severity: High] Can this cause a use-after-free? If self.fwnode was originally None, but the C subsystem matches and assigns an fwnode from elsewhere (e.g. the parent device), this drop logic will wrongly assume ownership of it and drop an unowned ARef. --=20 Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260805-rust_leds-= [email protected]?part=3D3