CVE-2026-98563: net: phylink: record the PHY only once bringup cannot fail
In the Linux kernel, the following vulnerability has been resolved:
net: phylink: record the PHY only once bringup cannot fail
phylinkbringupphy() stores the PHY in pl->phydev before its last fallible step: on a MAC whose phylink ops implement LPI, phyeeerxclockstop() can fail with a real MDIO error. The callers unwind with phydetach(), which knows nothing about pl->phydev, so a pointer to a PHY that is no longer attached outlives the failed connect.
What that costs depends on how the caller got here. phylinkconnectphy() goes through phylinkattachphy(), which refuses to attach while pl->phydev is set, turning a transient MDIO error into a permanent -EBUSY. The SFP path is worse than that: sfpsmprobephy() answers the failure with phydeviceremove() and phydevicefree(), and it assigns sfp->modphy only past that error return, so nothing clears pl->phydev and it is left pointing at a freed phydevice that phylinkresolve() and the ethtool helpers go on reading. phylinkfwnodephyconnect() has no such check, so a later connect overwrites the stale pointer and hides the problem. A disconnect does not: phylinkdisconnectphy() hands that pointer to phydisconnect(), and the second phydetach() on the same PHY drops references the first one already released.
Found while making a DSA port survive a PHY whose driver arrives after the switch probes: keeping the port across a failed connect and retrying is what makes this window reachable.
Publish the pointer after the last call that can fail instead of unwinding it afterwards. Nothing between the two points reads pl->phydev, and the registration that follows cannot fail: phyrequestinterrupt() falls back to polling on its own. The PHY-side state keeps the order it had, so no MDIO operation moves relative to another.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
ubuntu/linux-hwe-7.0to a version that resolves this vulnerability.Fixed in 7.0.0-42.42~24.04.1 - Upgrade
Upgrade
ubuntu/linux-riscv-7.0to a version that resolves this vulnerability.Fixed in 7.0.0-42.42.1~24.04.1 - Upgrade
Upgrade
ubuntu/linuxto a version that resolves this vulnerability.Fixed in 7.0.0-42.42 - Upgrade
Upgrade
ubuntu/linux-awsto a version that resolves this vulnerability.Fixed in 7.0.0-1016.17 - Upgrade
Upgrade
ubuntu/linux-gcpto a version that resolves this vulnerability.Fixed in 7.0.0-1016.18 - Upgrade
Upgrade
ubuntu/linux-ibmto a version that resolves this vulnerability.Fixed in 7.0.0-1017.17 - Upgrade
Upgrade
ubuntu/linux-oem-7.0to a version that resolves this vulnerability.Fixed in 7.0.0-1017.17 - Upgrade
Upgrade
ubuntu/linux-oracleto a version that resolves this vulnerability.Fixed in 7.0.0-1015.16 - Upgrade
Upgrade
ubuntu/linux-riscvto a version that resolves this vulnerability.Fixed in 7.0.0-42.42.1
Event History
Frequently Asked Questions
Which systems are exposed to the failed-connect condition?
Systems using phylink with MAC operations that implement LPI are exposed when phy_eee_rx_clock_stop() encounters a real MDIO error during PHY bring-up. The impact differs by connection path, with the SFP PHY probe path retaining a pointer to a freed phy_device.
What does an attacker or triggering condition need to cause this issue?
The issue is triggered by a PHY bring-up failure at the final phy_eee_rx_clock_stop() step, specifically a real MDIO error on an LPI-capable MAC. The provided information does not identify a remote attacker requirement.
What symptoms can indicate a system has encountered the issue?
For phylink_connect_phy(), a transient MDIO error can make later attachment attempts fail permanently with -EBUSY because pl->phydev remains set. On the SFP path, subsequent phylink resolution or ethtool operations may read a stale pointer after the PHY device has been removed and freed.
Does reconnecting always clear the stale PHY state?
No. A later phylink_fwnode_phy_connect() can overwrite the stale pointer and hide the condition, but a disconnect does not safely resolve it because phylink_disconnect_phy() passes the stale pointer to phy_disconnect().