In the Linux kernel, the following vulnerability has been resolved:
driver core: Fix uevent_show() vs driver detach race
ueventshow() wants to de-reference dev->driver->name. There is no clean way for a device attribute to de-reference dev->driver unless that attribute is defined via (struct devicedriver).devgroups. Instead, the anti-pattern of taking the devicelock() in the attribute handler risks deadlocks with code paths that remove device attributes while holding the lock.
This deadlock is typically invisible to lockdep given the devicelock() is marked lockdepsetnovalidateclass(), but some subsystems allocate a local lockdep key for @dev->mutex to reveal reports of the form:
====================================================== WARNING: possible circular locking dependency detected 6.10.0-rc7+ #275 Tainted: G OE N
modprobe/2374 is trying to acquire lock: ffff8c2270070de0 (kn->active#6){++++}-{0:0}, at: _kernfsremove+0xde/0x220
but task is already holding lock: ffff8c22016e88f8 (&cxlrootkey){+.+.}-{3:3}, at: devicereleasedriver_internal+0x39/0x210
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (&cxlrootkey){+.+.}-{3:3}: _mutexlock+0x99/0xc30 ueventshow+0xac/0x130 devattrshow+0x18/0x40 sysfskfseqshow+0xac/0xf0 seqreaditer+0x110/0x450 vfsread+0x25b/0x340 ksysread+0x67/0xf0 dosyscall64+0x75/0x190 entrySYSCALL64afterhwframe+0x76/0x7e
-> #0 (kn->active#6){++++}-{0:0}: _lockacquire+0x121a/0x1fa0 lockacquire+0xd6/0x2e0 kernfsdrain+0x1e9/0x200 _kernfsremove+0xde/0x220 kernfsremovebynamens+0x5e/0xa0 devicedel+0x168/0x410 deviceunregister+0x13/0x60 devresreleaseall+0xb8/0x110 deviceunbindcleanup+0xe/0x70 devicereleasedriverinternal+0x1c7/0x210 driverdetach+0x47/0x90 busremovedriver+0x6c/0xf0 cxlacpiexit+0xc/0x11 [cxlacpi] _dosysdeletemodule.isra.0+0x181/0x260 dosyscall64+0x75/0x190 entrySYSCALL64after_hwframe+0x76/0x7e
The observation though is that driver objects are typically much longer lived than device objects. It is reasonable to perform lockless de-reference of a @driver pointer even if it is racing detach from a device. Given the infrequency of driver unregistration, use synchronizercu() in moduleremovedriver() to close any potential races. It is potentially overkill to suffer synchronizercu() just to handle the rare module removal racing uevent_show() event.
Thanks to Tetsuo Handa for the debug analysis of the syzbot report [1].