CVE-2026-90144: dpll: fix NULL deref in dpll_device_ops() during teardown race
In the Linux kernel, the following vulnerability has been resolved:
dpll: fix NULL deref in dplldeviceops() during teardown race
When the last owner of a dpll device unregisters while a foreign driver still holds a pin on it via dpllpinonpinregister(), the dpll object stays alive with an empty registration list. A pin notification queued before the unregister (e.g. ice reacting to zl3073xi2c removal) then walks pin->dpllrefs into dplldeviceops(), which trips the WARNON and dereferences the missing registration. dplllock cannot help because the notification work was queued before the unregistering driver took the lock.
Treat the empty registration list as a legitimate transient state. Make dpllpriv() and dplldeviceops() return NULL in that case and make every pin netlink path that resolves a device from a pin skip such dplls. dpllcmdpingetone() picks a ref with a live registration and returns -ENODEV when there is none, the pin dumpit skips such a pin instead of aborting the dump, dpllmsgaddpindplls() and the frequency, esync, reference sync and phase adjust set paths skip dead refs, and dpllpinparentdeviceset() validates the parent with dplldevicegetbyid(). dpllpinregister() is the last caller that dereferenced the device ops without a check, so move its frequency monitor validation under dplllock and tolerate a missing registration there as well.
The empty registration list is equivalent to a cleared DPLLREGISTERED mark, both transitions happen under dplllock in dplldeviceregister() and dplldeviceunregister(). A pin notification for a pin whose dplls are all gone is now dropped with -ENODEV instead of crashing, all callers in the core ignore that return value.
WARNING: drivers/dpll/dpllcore.c:1092 at dplldeviceops+0x24/0x40, CPU#83: kworker/u576:3/23471 Modules linked in: ... ice ... zl3073xi2c(-) ... zl3073x ... Workqueue: icedpllwq icedpllpinnotifywork [ice] RIP: 0010:dplldeviceops+0x24/0x40 Call Trace: <TASK> dpllcmdpingetone+0x336/0x520 dpllpineventsend+0x82/0x140 dpllpinonpinunregister+0xbb/0x160 icedpllpinnotifywork+0x1bc/0x1f0 [ice] processonework+0x19e/0x370 workerthread+0x1a6/0x310 kthread+0xe4/0x120 retfromfork+0x1a1/0x270 retfromforkasm+0x1a/0x30 </TASK> ---[ end trace 0000000000000000 ]--- BUG: kernel NULL pointer dereference, address: 0000000000000010 #PF: supervisor read access in kernel mode #PF: errorcode(0x0000) - not-present page
Affected Software
Event History
Frequently Asked Questions
Which deployments can encounter this issue?
Systems using DPLL devices can encounter it when the last owner unregisters a DPLL device while another driver still holds a pin registered through dpll_pin_on_pin_register(). The affected state is an otherwise live DPLL object with an empty registration list.
What sequence triggers the failure?
A pin notification must have been queued before the owning driver unregisters. When that notification later resolves the pin's DPLL references, it can reach dpll_device_ops() with no registration present, causing a WARN_ON and a NULL dereference.
How would an affected system behave?
The failure is associated with a WARN_ON followed by a NULL-pointer dereference while processing queued pin notifications. The fixed handling returns -ENODEV when no live registration can be selected for a pin and skips dead DPLL references in relevant pin netlink and configuration paths.