All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Markus Probst" <markus.probst@posteo.de>
Cc: linux-pci@vger.kernel.org, ojeda@kernel.org,
	linux-leds@vger.kernel.org, lee@kernel.org
Subject: Re: [PATCH v21 1/3] rust: leds: add basic led classdev abstractions
Date: Mon, 29 Jun 2026 13:36:27 +0000	[thread overview]
Message-ID: <20260629133627.A68C11F00A3A@smtp.kernel.org> (raw)
In-Reply-To: <20260629-rust_leds-v21-1-4f0f19579db5@posteo.de>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] The `blink_set_callback` creates multiple mutable references (`&mut usize`) to the same shared memory concurrently, violating Rust's strict aliasing rules.
- [High] The `DeviceBuilder::build` method erases the lifetime of the `name` string, allowing the `led_classdev.name` pointer to outlive the string and causing a Use-After-Free.
- [High] Unsound `FwNode` reference count management in `Device::drop` retrieves the `fwnode` directly from the mutable C structure, leading to refcount underflow and Use-After-Free.
--

commit d59e3e50bab36d2a8936041aa09ed5823876969f
Author: Markus Probst <markus.probst@posteo.de>

rust: leds: add basic led classdev abstractions

Implement the core abstractions needed for led class devices, including
LedOps, DeviceBuilder, and Device.

> diff --git a/rust/kernel/led/normal.rs b/rust/kernel/led/normal.rs
> new file mode 100644
> index 0000000000000..2769f690bb245
> --- /dev/null
> +++ b/rust/kernel/led/normal.rs

[ ... ]

> +impl<'a, S: DeviceBuilderState> DeviceBuilder<'a, S> {
> +    /// Registers a new [`Device`].
> +    pub fn build<'bound: 'a, T: LedOps + 'bound>(
> +        self,
> +        parent: &'bound T::Bus,
> +        ops: impl PinInit<T, Error> + 'a,
> +    ) -> impl PinInit<Device<'bound, T>, Error> + 'a {

[Severity: High]
Is the lifetime bound <'bound: 'a> backwards here?

By specifying 'bound: 'a, the returned Device ('bound) is explicitly permitted
to outlive the builder's string lifetime ('a).

Because the raw pointer to this string is written directly into the
led_classdev.name field, a driver could initialize a Device with a temporary
string, which drops the string while leaving led_cdev->name dangling. Can
this lead to a use-after-free?

[ ... ]

> +    unsafe extern "C" fn blink_set_callback(
> +        led_cdev: *mut bindings::led_classdev,
> +        delay_on: *mut usize,
> +        delay_off: *mut usize,
> +    ) -> i32 {
> +        from_result(|| {
> +            // SAFETY: The function's contract guarantees that `led_cdev` is a valid pointer to a
> +            // `led_classdev` embedded within a `led::Device`.
> +            let classdev = unsafe { Device::<T>::from_raw(led_cdev) };
> +            // SAFETY: `classdev.parent()` is guaranteed to be contained in `T::Bus`.
> +            let parent = unsafe { T::Bus::from_device(classdev.parent()) };
> +
> +            classdev.ops.blink_set(
> +                parent,
> +                classdev,
> +                // SAFETY: The function's contract guarantees that `delay_on` points to a `usize`
> +                // and is exclusive for the period of this function.
> +                unsafe { &mut *delay_on },
> +                // SAFETY: The function's contract guarantees that `delay_off` points to a `usize`
> +                // and is exclusive for the period of this function.
> +                unsafe { &mut *delay_off },
> +            )?;

[Severity: High]
Could this lead to a strict aliasing violation by creating multiple mutable
references to the same shared memory concurrently?

In the C LED subsystem, sysfs write operations to delay_on and delay_off can
invoke led_blink_set() concurrently across different threads without holding
locks on the device.

This passes pointers to the shared led_cdev->blink_delay_on and
led_cdev->blink_delay_off fields directly into the blink_set callback. By
unconditionally casting these raw C pointers to &mut usize in Rust, the
callback can create overlapping mutable references to the exact same memory
locations.

[ ... ]

> +#[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]
Does this unsoundly steal a reference count from the C field dev->fwnode?

In DeviceBuilder::build, self.fwnode is passed to C and its refcount is
leaked via core::mem::forget. However, if self.fwnode was initially None, no
reference count is leaked.

If dev->fwnode is subsequently populated by external C code, this
PinnedDrop implementation blindly constructs an ARef and drops it. Since
Rust never incremented this refcount, could this result in an underflow
and an eventual use-after-free of the FwNode?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260629-rust_leds-v21-0-4f0f19579db5@posteo.de?part=1

  reply	other threads:[~2026-06-29 13:36 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-29 13:10 [PATCH v21 0/3] rust: leds: add led classdev abstractions Markus Probst
2026-06-29 13:10 ` [PATCH v21 1/3] rust: leds: add basic " Markus Probst
2026-06-29 13:36   ` sashiko-bot [this message]
2026-07-02 10:47   ` Alice Ryhl
2026-07-02 11:00     ` Markus Probst
2026-07-02 11:22       ` Alice Ryhl
2026-07-02 11:09     ` Gary Guo
2026-06-29 13:10 ` [PATCH v21 2/3] rust: leds: add Mode trait Markus Probst
2026-06-29 13:40   ` sashiko-bot
2026-06-29 13:10 ` [PATCH v21 3/3] rust: leds: add multicolor classdev abstractions Markus Probst
2026-06-29 13:55   ` 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=20260629133627.A68C11F00A3A@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 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.