Re: [PATCH v19 4/7] driver core: do not always lock parent in shutdown

[email protected] Fri, 31 Jul 2026 23:19:22 +0000
Newsgroups org.kernel.vger.linux-scsi,dev.linux.lists.sashiko-reviews,org.kernel.vger.linux-pci
Message-ID <[email protected]>
David Jeffery <[email protected]> writes:

> On Thu, Jul 16, 2026 at 10:59=E2=80=AFPM <[email protected]> wrote:
>>
>> Thank you for your contribution! Sashiko AI review found 2 potential iss=
ue(s) to consider:
>>
>> New issues:
>> - [High] Unprotected read of dev->parent introduces a Use-After-Free rac=
e with device_move() during reference acquisition.
>>
>> Pre-existing issues:
>> - [High] Dropping and re-acquiring device_lock(dev) allows dev->parent t=
o change, resulting in locking an obsolete parent.
>
> We could add additional locking around device_move to exclude moves
> during these times to quiet both the AI tool's concerns. However, both
> these concerns are already not possible in reality. The only user of
> need_parent_lock in the kernel which will use this code path is usb
> devices, and none of the rare devices which use device_move will move
> a usb device which has need_parent_lock set. Thus, there is no actual
> device_move which can cause these conditions the AI tool complains
> about.
>
> The AI tool is finding a non-existent issue by applying a very
> specific special state as a general condition. If really wanted, I
> could add a patch which locks out moves during these times as a form
> of future-proofing, but from my view of the code all it would be doing
> is creating additional code and complexity to the driver core while
> currently fixing nothing.
>

I agree, it is very special case. device_move is associated with virtual
devices only and need_parent_lock is used with phsyical bus (Only with
USB) to prevent port reset during device probe/unbind. Even in future,
I dont see a need where a virtual device using device_move will need
need_parent_lock ever.

But I suggest, We can add the comment like:

/*
 * device_move() should not be used on devices with need_parent_lock
 * set, as concurrent reparenting during device_shutdown() introduces
 * a potential race when locking the parent device.
 */

WDYT?

~Tarun


>> --
>>
>> --- Patch [4]: [PATCH v19 4/7] driver core: do not always lock parent in=
 shutdown ---
>> commit 6be56e5bea0fe214a5199c9f806c49e62e60127f
>> Author: David Jeffery <[email protected]>
>>
>> driver core: do not always lock parent in shutdown
>>
>> This patch modifies the device shutdown process to only lock a parent de=
vice
>> if it is strictly needed, rather than unconditionally. It also defers
>> acquiring a reference to the parent device until the point where the par=
ent
>> needs to be locked.
>>
>> > diff --git a/drivers/base/core.c b/drivers/base/core.c
>> > index 82a7af1f3ba2e..31f95e86856e0 100644
>> > --- a/drivers/base/core.c
>> > +++ b/drivers/base/core.c
>>
>> [ ... ]
>>
>> > @@ -4925,12 +4921,32 @@ static void shutdown_one_device(struct device =
*dev)
>> >  static void shutdown_one_device(struct device *dev)
>> >  {
>> > +     struct device *parent;
>> > +
>> > +     device_lock(dev);
>> > +
>> > +     /* use parent lock if needed to avoid race with probe/release */
>> > +     if (dev->bus && dev->bus->need_parent_lock && dev->p && !dev->p-=
>dead &&
>> > +         (parent =3D get_device(dev->parent))) {
>>
>> [Severity: High]
>> Does moving the parent reference acquisition out of the list_lock critic=
al
>> section introduce a race condition where the parent could be freed?
>>
>> In device_shutdown(), get_device(dev->parent) was previously called whil=
e
>> holding devices_kset->list_lock. Now that it is evaluated locklessly in
>> shutdown_one_device():
>>
>> CPU1
>> shutdown_one_device()
>>     evaluates dev->parent, but is preempted before get_device() is calle=
d
>>
>> CPU2
>> device_move()
>>     changes dev->parent and calls put_device(old_parent)
>>     dropping the last reference and freeing the memory
>>
>> When CPU1 resumes, could it pass the freed pointer into get_device() and
>> dereference it?
>>
>> > +             /* the parent lock needs to be acquired first, so re-loc=
k */
>> > +             device_unlock(dev);
>> > +
>> > +             device_lock(parent);
>> > +             device_lock(dev);
>> > +
>> > +             __shutdown_one_device(dev);
>>
>> [Severity: High]
>> This is a pre-existing issue, but does dropping and re-acquiring the dev=
ice
>> lock here allow the topology to change?
>>
>> If a concurrent device_move() reparents the device while device_lock(dev=
)
>> is dropped, it appears we might lock the obsolete parent. When we re-loc=
k
>> dev and call __shutdown_one_device(), we haven't verified that dev->pare=
nt
>> still matches the locked parent.
>>
>> Could this defeat the need_parent_lock synchronization and allow a
>> concurrent probe or release on the new parent to race with the shutdown?
>>
>> > +             device_unlock(dev);
>> >               device_unlock(parent);
>> > +             put_device(parent);
>> > +     } else {
>> > +             __shutdown_one_device(dev);
>> > +             device_unlock(dev);
>> > +     }
>> >
>> >       put_device(dev);
>> >  }
>>
>> --
>> Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260716230411.2=
[email protected]?part=3D4
>>