Re: [PATCH v9 2/2] platform: Add initial synology microp driver

Markus Probst <[email protected]>
Newsgroups dev.linux.lists.sashiko
Message-ID <[email protected]>
On Thu, 2026-04-23 at 21:58 +0000, [email protected] wrote:
> Sashiko AI review found 7 potential issue(s):
> - [Critical] Use-After-Free of the dynamically allocated Alert LED CString.
> - [High] Logic errors in LED brightness control prevent clearing the hardware blink state.
> - [High] Use-After-Free of `power_name` during teardown due to incorrect struct field declaration order.
> - [High] Concurrent accesses to the shared serdev bus are not serialized, leading to corrupted command sequences.
> - [Medium] The SYNOLOGY_MICROP config depends on a non-existent symbol RUST_SERIAL_DEV_BUS_ABSTRACTIONS.
> - [Medium] Typo in the compatible string for the DS223 model prevents driver binding.
> - [Low] Missing Device Tree Binding YAML file referenced in MAINTAINERS.
> --
Since this is an AI reply, I am not sure if I am supposed to reply to
it. Anyway, the answers:

> 
> commit 47c26ce6bffc3c75c3df285181d595c18b827e6e
> Author: Markus Probst <[email protected]>
> 
> platform: Add initial synology microp driver
> 
> Add a initial synology microp driver, written in Rust. The driver targets
> a microcontroller found in Synology NAS devices.
> 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -25546,6 +25546,13 @@ F:	drivers/dma-buf/sync_*
> >  F:	include/linux/sync_file.h
> >  F:	include/uapi/linux/sync_file.h
> >  
> > +SYNOLOGY MICROP DRIVER
> > +M:	Markus Probst <[email protected]>
> > +L:	[email protected]
> > +S:	Maintained
> > +F:	Documentation/devicetree/bindings/embedded-controller/synology,ds918p-microp.yaml
> 
> Is this YAML file missing from the patch? It doesn't appear to be included
> in the commit, which will cause Device Tree binding checks to miss the new
> schema.
It was added in the previous patch.

> 
> > diff --git a/drivers/platform/synology_microp/Kconfig b/drivers/platform/synology_microp/Kconfig
> > --- /dev/null
> > +++ b/drivers/platform/synology_microp/Kconfig
> > @@ -0,0 +1,13 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +config SYNOLOGY_MICROP
> > +	tristate "Synology Microp driver"
> > +	depends on LEDS_CLASS && LEDS_CLASS_MULTICOLOR
> > +	depends on RUST_SERIAL_DEV_BUS_ABSTRACTIONS
> 
> Does RUST_SERIAL_DEV_BUS_ABSTRACTIONS exist anywhere in the tree?
> 
> Depending on a non-existent symbol causes a silent build failure where the
> dependency can never be satisfied, rendering the driver unbuildable.
Its in the serdev dependency of the patch.

> 
> > diff --git a/drivers/platform/synology_microp/command.rs b/drivers/platform/synology_microp/command.rs
> > --- /dev/null
> > +++ b/drivers/platform/synology_microp/command.rs
> [ ... ]
> > +impl Command {
> > +    pub(crate) fn write(self, dev: &serdev::Device<Bound>) -> Result {
> > +        dev.write_all(
> 
> Does this code prevent concurrent writes to the serial bus?
> 
> If user space modifies the state of multiple LEDs concurrently, the LED
> subsystem will invoke their callbacks simultaneously. Without a shared lock
> protecting the single serdev::Device instance, the multi-byte command
> sequences can become interleaved and corrupt the serial protocol.
If I send it as one buffer, I expect it to be sent in this order, even
if another thread trys to do the same.

Even if the whole buffer is not accepted at once. serdev internally
locks a mutex.

> 
> > diff --git a/drivers/platform/synology_microp/led.rs b/drivers/platform/synology_microp/led.rs
> > --- /dev/null
> > +++ b/drivers/platform/synology_microp/led.rs
> [ ... ]
> > +#[pin_data]
> > +pub(crate) struct Data {
> > +    #[pin]
> > +    status: Devres<led::MultiColorDevice<StatusLedHandler>>,
> > +    power_name: CString,
> > +    #[pin]
> > +    power: Devres<led::Device<LedHandler>>,
> > +}
> 
> Does this struct declaration order create a use-after-free during driver
> unbind?
> 
> In Rust, struct fields are dropped strictly in declaration order. Because
> power_name is declared before power, its backing string buffer is freed
> before the Devres destructor unregisters the LED from the C subsystem.
> 
> This creates a time window where the active led_classdev holds a dangling
> pointer to its name.
The CString is only ever used on register and is copied by the led
subsystem. The field does not have to outlive the `led::Device`.

> 
> [ ... ]
> > +impl Data {
> > +    pub(super) fn register<'a>(
> > +        dev: &'a serdev::Device<Bound>,
> > +        model: &'a Model,
> > +    ) -> impl PinInit<Self, Error> + 'a {
> > +        pin_init_scope(move || {
> > +            if let Some(color) = model.led_alert {
> > +                let name = CString::try_from_fmt(fmt!("{}:alarm", color.as_c_str().to_str()?))?;
> > +                devres::register(
> > +                    dev.as_ref(),
> > +                    led::DeviceBuilder::new().color(color).name(&name).build(
> 
> Could this leak a dangling pointer to the LED subsystem?
> 
> The name variable is strictly local to this if let block. When the block
> ends, the string is dropped and its backing memory is freed, but the kernel's
> LED framework expects the name string pointer to remain valid for the
> lifetime of the device.
The CString is only ever used on register and is copied by the led
subsystem. The field does not have to outlive the `led::Device`.

> 
> [ ... ]
> > +    fn brightness_set(
> > +        &self,
> > +        dev: &Self::Bus,
> > +        _classdev: &led::Device<Self>,
> > +        brightness: u32,
> > +    ) -> Result<()> {
> > +        let mut blink = self.blink.lock();
> > +        (self.command)(if brightness == 0 {
> > +            *blink = false;
> > +            State::Off
> > +        } else if *blink {
> > +            State::Blink
> > +        } else {
> > +            State::On
> > +        })
> 
> If brightness is non-zero, shouldn't this disable any active blinking and set
> the LED solidly ON?
> 
> Evaluating else if *blink when brightness > 0 means the LED continues to
> blink and the internal boolean flag is never cleared.
No, only brightness = 0 disables blinking.
> 
> [ ... ]
> > +    fn blink_set(
> > +        &self,
> > +        dev: &Self::Bus,
> > +        _classdev: &led::Device<Self>,
> > +        delay_on: &mut usize,
> > +        delay_off: &mut usize,
> > +    ) -> Result<()> {
> > +        let mut blink = self.blink.lock();
> > +
> > +        (self.command)(if *delay_on == 0 && *delay_off != 0 {
> > +            State::Off
> 
> Should this path also reset *blink to false when blinking is explicitly
> stopped?
You are right on this one.

> 
> [ ... ]
> > +    fn brightness_set(
> > +        &self,
> > +        dev: &Self::Bus,
> > +        classdev: &led::MultiColorDevice<Self>,
> > +        brightness: u32,
> > +    ) -> Result<()> {
> > +        let mut blink = self.blink.lock();
> > +        if brightness == 0 {
> > +            *blink = false;
> > +        }
> > +
> > +        let (color, subled_brightness) = if classdev.subleds()[1].intensity == 0 {
> > +            (StatusLedColor::Green, classdev.subleds()[0].brightness)
> > +        } else {
> > +            (StatusLedColor::Orange, classdev.subleds()[1].brightness)
> > +        };
> > +
> > +        Command::StatusLed(
> > +            color,
> > +            if subled_brightness == 0 {
> > +                State::Off
> > +            } else if *blink {
> > +                State::Blink
> > +            } else {
> > +                State::On
> > +            },
> 
> Similarly, does this fail to turn a blinking LED solidly ON when the
> brightness is non-zero? It looks like it will just keep blinking because the
> blink state isn't cleared.
No, only brightness = 0 disables blinking.
> 
> > diff --git a/drivers/platform/synology_microp/synology_microp.rs b/drivers/platform/synology_microp/synology_microp.rs
> > --- /dev/null
> > +++ b/drivers/platform/synology_microp/synology_microp.rs
> [ ... ]
> > +        // rtd1619b
> > +        (DeviceId::new(c"synolody,ds223-microp"), Model::new().led_usb_copy()),
> 
> This isn't a bug, but there's a typo in the vendor prefix ("synolody"). This
> will prevent the driver from matching the device tree node for the ds223.
Yes, that is not supposed to be there.

Thanks
- Markus Probst
signature.asc (application/pgp-signature, 870 B)
-----BEGIN PGP SIGNATURE-----

iQJPBAABCAA5FiEEgnQYxPSsWOdyMMRzNHYf+OetQ9IFAmnrWvQbFIAAAAAABAAO
bWFudTIsMi41KzEuMTIsMiwyAAoJEDR2H/jnrUPS0wMP/i5ZzCynEx69I1+I8tNa
GmU/6JgfjGQIS8VTEjeZPnhlScj+XTtZpMZZA3sOahsDpjR2hMWXHdhy4MHtI/81
kMErwVgTMZx8LP26t/4TI06dHcyalgYRcp4h5lSUP9Nfp9LASNL5phAURdys++4p
Kw5xQgb2pGYCKlPlX5QG2hd1iOvUdarBAVTtIZT1y0SlUgG1SSR7DIDkBQixHgnT
AJthCJQ+BRRP+sxMBquqAvyEU87Z9PpoPyiZf4CcOrFnDmLdMI6+Wf6cLRtAK655
NSky73ADQVps7CVMz54qFbFioUHwNUZstM0+/tr8rshdhl5crofqfxVvzqzDRUwx
tIY+miLEtR56w2V/wj7guxzs3VCC0NnLdI4IncYoaUg0vKN0kOPtPHyF/YLFCQzw
tbO7zrRFdTRYYQX8/ldTV6fbHQ44qw1leMe/lI4/JPRT9AYA4PTBHm8zNrDAyByA
vk6y2OICfbyeuXFgqLafyl5JW02s6P2VYs2zCIYb7t1szKwc99yGSPOhNzWN8Nn3
X+w5ZpGmW3O1FxNjdJZjuSenjvK5U5KCXMNJ5M5SaJfCjYH+jhppNCEBYopjM7Ov
W01aIaiDv2vC1nfzXgEiRcWP8U5isAx1uP7U79ah3jjmL0FIfntyhKC5hG82CfiC
abdzONaptTqcjlob2b/0BRmh
=ffPI
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.