`Registration::drop` called `drm_dev_unregister()`, which is only safe when no userspace clients still hold the device open. For a DRM device on a hot-removable bus (e.g. a USB dock) the device can disappear while a compositor holds its `card`/`render` node, and tearing it down with `drm_dev_unregister()` leaves that fd pointing at freed device state — a use-after-free on the next ioctl/mmap.
Use `drm_dev_unplug()` instead: the hot-unplug-safe superset. It sets `dev->unplugged` (so the DRM ioctl/mmap paths return -ENODEV to held fds), drains in-flight `drm_dev_enter`/`drm_dev_exit` critical sections via SRCU, unregisters the minors, and unmaps userspace mappings. For a permanent device it behaves like `drm_dev_unregister()` plus the harmless unplugged flag at the very end of its life, so it is safe unconditionally. Signed-off-by: Mike Lothian <[email protected]> Assisted-by: Claude:claude-opus-4-8 [Claude-Code] --- rust/kernel/drm/driver.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs index 25f7e233884d..aa86ba136b03 100644 --- a/rust/kernel/drm/driver.rs +++ b/rust/kernel/drm/driver.rs @@ -135,7 +135,15 @@ pub trait Driver { /// The registration type of a `drm::Device`. /// -/// Once the `Registration` structure is dropped, the device is unregistered. +/// Once the `Registration` structure is dropped, the device is unplugged (which also +/// unregisters it). [`drm_dev_unplug`] is the hot-unplug-safe teardown: it sets the device's +/// `unplugged` flag (so the DRM ioctl/mmap paths return `-ENODEV` to any process still holding +/// an open `card`/`render` node, rather than dereferencing freed device state), drains +/// in-flight `drm_dev_enter`/`drm_dev_exit` critical sections, unregisters the minors, and tears +/// down userspace mappings. For devices on a removable bus (e.g. a USB dock) this is required +/// for safe removal; for permanent devices it is a harmless superset of `drm_dev_unregister`. +/// +/// [`drm_dev_unplug`]: https://docs.kernel.org/gpu/drm-internals.html pub struct Registration<T: Driver>(ARef<drm::Device<T>>); impl<T: Driver> Registration<T> { @@ -197,7 +205,9 @@ unsafe impl<T: Driver> Send for Registration<T> {} impl<T: Driver> Drop for Registration<T> { fn drop(&mut self) { // SAFETY: Safe by the invariant of `ARef<drm::Device<T>>`. The existence of this - // `Registration` also guarantees the this `drm::Device` is actually registered. - unsafe { bindings::drm_dev_unregister(self.0.as_raw()) }; + // `Registration` also guarantees that this `drm::Device` is actually registered. + // `drm_dev_unplug` is the hot-unplug-safe teardown (it calls `drm_dev_unregister` + // internally after marking the device unplugged) — see the type's documentation. + unsafe { bindings::drm_dev_unplug(self.0.as_raw()) }; } } -- 2.54.0
