Skip to content

Fix dangling dev->driver pointer when unloading a driver with probed-but-not-attached devices#2208

Open
MegaManSec wants to merge 1 commit into
freebsd:mainfrom
MegaManSec:hms-driver-dangling-ptr
Open

Fix dangling dev->driver pointer when unloading a driver with probed-but-not-attached devices#2208
MegaManSec wants to merge 1 commit into
freebsd:mainfrom
MegaManSec:hms-driver-dangling-ptr

Conversation

@MegaManSec

@MegaManSec MegaManSec commented May 18, 2026

Copy link
Copy Markdown
Contributor

Problem

When a driver module is unloaded, devclass_driver_deleted() calls device_detach() for each device using that driver. However, device_detach() is a no-op if the device is not in DS_ATTACHED state — it returns 0 immediately without clearing dev->driver.

This occurs whenever a device was successfully probed (setting dev->driver into module memory and transitioning to DS_ALIVE) but attach was never reached — most commonly because device_attach() returned early on a resource_disabled() hint check. After kldunload, dev->driver is a dangling pointer into freed module pages.

A subsequent sysctl hw.bus.devices query (e.g. from devmatch) calls sysctl_devices(), which dereferences dev->driver->name — triggering a page fault and kernel panic.

This affects any loadable driver whose probe succeeds but whose attach is blocked by hints. The entire HID leaf driver family (hms, hkbd, hcons, hmt, hpen, hgame, hidraw, bcm5974, appleir, hconf, hsctrl, ietp, ps4dshock, u2f, wmt, xb360gp) is in this category, as none perform their own resource_disabled() check in probe.

Fix

After device_detach() returns in devclass_driver_deleted(), check whether dev->driver still points at the departing driver and call device_set_driver(dev, NULL) to release it before the module is freed.

Reproducer

hint.hms.0.disabled="1"   # in /boot/device.hints

Boot, then kldunload hms (or wait for devmatch to run). Kernel panics in sysctl_devices() with a page fault at the address where hms.ko was mapped.

@github-actions

github-actions Bot commented May 18, 2026

Copy link
Copy Markdown

Thank you for taking the time to contribute to FreeBSD!

All issues resolved.

@MegaManSec

Copy link
Copy Markdown
Contributor Author

This resolves https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=280714.

@MegaManSec MegaManSec force-pushed the hms-driver-dangling-ptr branch from 9d41756 to 2866a32 Compare May 18, 2026 16:25
Comment thread sys/kern/subr_bus.c Outdated
Comment thread sys/kern/subr_bus.c
* it cannot dangle into the unloaded module.
*/
if (dev->driver == driver)
(void)device_set_driver(dev, NULL);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need the (void) cast here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

device_set_driver() is cast to void everywhere else in this file

@bsdimp

bsdimp commented May 18, 2026

Copy link
Copy Markdown
Member

Generally I like it, but had a few suggestions to make it better.

@bsdimp bsdimp self-assigned this May 18, 2026
@bsdimp bsdimp added the changes-required Cannot land as is, change requested of submitter label May 18, 2026
@MegaManSec MegaManSec force-pushed the hms-driver-dangling-ptr branch 2 times, most recently from 19de0a4 to 14a598b Compare May 18, 2026 16:30
@MegaManSec MegaManSec changed the title subr_bus: clear dev->driver for probed-but-not-attached devices on unload Fix dangling dev->driver pointer when unloading a driver with probed-but-not-attached devices May 18, 2026
…load

device_detach() is a no-op when dev->state != DS_ATTACHED, so if a
driver was matched during probe but attach was never reached (e.g. the
device is disabled via hints), dev->driver is left pointing into the
module's data segment after the module is unloaded.

devclass_driver_deleted() already iterates devices whose driver pointer
matches the driver being removed.  After calling device_detach(), check
whether the pointer is still set and call device_set_driver(dev, NULL)
to release it.  This prevents sysctl_devices() from dereferencing a
dangling pointer into freed module memory when enumerating hw.bus.devices.

Signed-off-by: Joshua Rogers <Joshua@Joshua.Hu>
@MegaManSec MegaManSec force-pushed the hms-driver-dangling-ptr branch from 14a598b to 447b17e Compare May 18, 2026 16:35
@MegaManSec MegaManSec requested a review from bsdimp May 18, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changes-required Cannot land as is, change requested of submitter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants