Re: [PATCH v19 3/7] driver core: separate function to shutdown one device

David Jeffery <[email protected]> Wed, 29 Jul 2026 09:45:27 -0400
Newsgroups org.kernel.vger.linux-scsi,dev.linux.lists.sashiko-reviews,org.kernel.vger.linux-pci
Message-ID <CANghDUVJNULztJ+-8G=PD9eXjdBF=QuHyXhYszzZO5rtzyj5ag@mail.gmail.com>
On Thu, Jul 16, 2026 at 10:50 PM <[email protected]> wrote:
>
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] The refactored `device_shutdown` discards the parent device pointer returned by `get_device(dev->parent)` and re-reads `dev->parent` inside `shutdown_one_device()`, creating a TOCTOU race condition that can lead to reference leaks and use-after-free.

This gets cleaned up in the next patch, but I'll rework it so that
this patch has no functional code changes and is only a code move into
a separate function.

> --
>
> --- Patch [3]: [PATCH v19 3/7] driver core: separate function to shutdown one device ---
> commit c3cdb15ac9b6efba6077cade25c652c124eaa9c7
> Author: David Jeffery <[email protected]>
>
> driver core: separate function to shutdown one device
>
> This commit refactors device_shutdown() by extracting the shutdown logic for a
> single device into a new separate function, shutdown_one_device(). This change
> is intended as a preparatory step for supporting asynchronous device shutdown.
>
> > diff --git a/drivers/base/core.c b/drivers/base/core.c
> > index 78b90326addb6..82a7af1f3ba2e 100644
> > --- a/drivers/base/core.c
> > +++ b/drivers/base/core.c
> > @@ -4898,12 +4898,48 @@ int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid)
> >       return error;
> >  }
> >
> > +static void shutdown_one_device(struct device *dev)
> > +{
> > +     struct device *parent = dev->parent;
>
> [Severity: High]
> Does this lockless read of dev->parent introduce a race condition?
>
> In the old code, the parent device pointer was captured and pinned in
> device_shutdown() using parent = get_device(dev->parent).
>
> With this refactoring, dev->parent is re-read here. If the parent changes
> concurrently (for example, via device_move()), could we end up operating on a
> parent device that we do not hold a reference to?
>
> > +
> > +     /* hold lock to avoid race with probe/release */
> > +     if (parent)
> > +             device_lock(parent);
>
> [ ... ]
>
> > @@ -4925,7 +4961,7 @@ void device_shutdown(void)
> >                * prevent it from being freed because parent's
> >                * lock is to be held
> >                */
> > -             parent = get_device(dev->parent);
> > +             get_device(dev->parent);
>
> [Severity: High]
> Is there a reference leak here since the return value of get_device() is now
> discarded?
>
> If dev->parent changes right after this call, the original parent's reference
> will be leaked. Later, shutdown_one_device() will lock and drop a reference
> to the new parent instead, potentially leading to unbalanced reference counts
> and use-after-free.
>
> Should we pass the pinned parent device pointer into shutdown_one_device()
> as an argument to ensure we lock and release the exact same device we took a
> reference to?
>
> >               get_device(dev);
> >               /*
> >                * Make sure the device is off the kset list, in the
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
>