* [PATCH] driver core: complete deferred binds when drivers_autoprobe is off
@ 2026-10-08 15:41 mosafer
0 siblings, 0 replies; only message in thread
From: mosafer @ 2026-10-08 15:41 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
Cc: driver-core, linux-usb, linux-kernel,
syzbot+863936f50214e843ae0c, Mohammad Mosafer, stable
From: Mohammad Mosafer <mohsafer@gmail.com>
device_add() registers a device and then runs the bus's initial probe
via bus_probe_device() -> device_initial_probe(). With
drivers_autoprobe disabled for the bus, device_initial_probe() skips
__device_attach() entirely.
That is correct for automatic *matching* against the bus's driver list,
but __device_attach() also doubles as "complete a bind that a driver
already initiated": when dev->driver has been pre-assigned outside the
normal match/probe path, its else-if branch finishes the bind by
calling device_bind_driver().
With autoprobe off, that second duty is skipped too. USB depends on
it: usb_driver_claim_interface() pre-sets dev->driver on an interface
that is not yet registered, documenting "let the future device_add()
bind it, bypassing probe()". Composite drivers (cdc-acm, cdc_ncm,
cdc_mbim, ...) rely on it to bind their sibling data interfaces. If
drivers_autoprobe is written with 0 while such an interface is
between the claim and its device_add(), the interface ends up
registered, with dev->driver set and iface->condition ==
USB_INTERFACE_BOUND, but never bound: its knode_driver is never
attached to the driver's klist_devices.
Teardown then trusts those flags: usb_driver_release_interface() ->
device_release_driver() -> __device_release_driver() runs a full
release and calls klist_remove(&dev->p->knode_driver) on a
never-attached node whose knode_klist() is NULL, which klist_put()
dereferences:
Oops: general protection fault
KASAN: null-ptr-deref in range [0x0000000000000058-0x000000000000005f]
klist_put <- klist_remove <- device_release_driver_internal <-
usb_driver_release_interface <- acm_disconnect / cdc_ncm_unbind
Reproduced with syzkaller's C reproducer on a 7.3.0-rc6 tree:
instrumentation shows the doomed interface's device_add() racing an
autoprobe=0 write; the bind-completion branch never runs for it; later
teardown hits klist_remove() with a pristine node. With this patch the
same instrumented race completes the bind inside the window (knode
attached, crash gone): 3 VMs, 5 min per run, race window hit and bind
completed 8 times, zero KLIST-REMOVE-BAD, zero Oops.
Gate the flag on what it means - automatic matching - not on the
completion of a bind the driver already requested: pass through to
__device_attach() when dev->driver is pre-set. Other subsystems that
preset dev->driver before device_add() (w1, tegra xusb,
zynqmp-ipi-mailbox) get the same correctness back; when dev->driver is
NULL the behavior is byte-for-byte unchanged.
Reported-by: syzbot+863936f50214e843ae0c@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=863936f50214e843ae0c
Fixes: b8c5cec23d5c ("Driver core: udev triggered device-<>driver binding")
Cc: stable@vger.kernel.org
Signed-off-by: Mohammad Mosafer <mohsafer@gmail.com>
---
drivers/base/dd.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index f6525a7ee8c5..98315264295e 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -1149,7 +1149,17 @@ void device_initial_probe(struct device *dev)
if (!sp)
return;
- if (sp->drivers_autoprobe)
+ /*
+ * The drivers_autoprobe flag only suppresses matching the device
+ * against the bus drivers. If a driver has already been assigned
+ * to the device (e.g. usb_driver_claim_interface() pre-setting
+ * dev->driver for an unregistered interface, expecting device_add()
+ * to complete the bind), the bind must be finished regardless of
+ * autoprobe: otherwise the device ends up registered with
+ * dev->driver set but never bound, and teardown oopses removing
+ * the never-attached knode_driver from the driver klist.
+ */
+ if (sp->drivers_autoprobe || dev->driver)
__device_attach(dev, true);
subsys_put(sp);
--
2.34.1
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-08 15:42 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-08 15:41 [PATCH] driver core: complete deferred binds when drivers_autoprobe is off mosafer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®