CVE-2025-39915

Severity CVSS v4.0:
Pending analysis
Type:
Unavailable / Other
Publication date:
01/10/2025
Last modified:
14/01/2026

Description

In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> net: phy: transfer phy_config_inband() locking responsibility to phylink<br /> <br /> Problem description<br /> ===================<br /> <br /> Lockdep reports a possible circular locking dependency (AB/BA) between<br /> &amp;pl-&gt;state_mutex and &amp;phy-&gt;lock, as follows.<br /> <br /> phylink_resolve() // acquires &amp;pl-&gt;state_mutex<br /> -&gt; phylink_major_config()<br /> -&gt; phy_config_inband() // acquires &amp;pl-&gt;phydev-&gt;lock<br /> <br /> whereas all the other call sites where &amp;pl-&gt;state_mutex and<br /> &amp;pl-&gt;phydev-&gt;lock have the locking scheme reversed. Everywhere else,<br /> &amp;pl-&gt;phydev-&gt;lock is acquired at the top level, and &amp;pl-&gt;state_mutex at<br /> the lower level. A clear example is phylink_bringup_phy().<br /> <br /> The outlier is the newly introduced phy_config_inband() and the existing<br /> lock order is the correct one. To understand why it cannot be the other<br /> way around, it is sufficient to consider phylink_phy_change(), phylink&amp;#39;s<br /> callback from the PHY device&amp;#39;s phy-&gt;phy_link_change() virtual method,<br /> invoked by the PHY state machine.<br /> <br /> phy_link_up() and phy_link_down(), the (indirect) callers of<br /> phylink_phy_change(), are called with &amp;phydev-&gt;lock acquired.<br /> Then phylink_phy_change() acquires its own &amp;pl-&gt;state_mutex, to<br /> serialize changes made to its pl-&gt;phy_state and pl-&gt;link_config.<br /> So all other instances of &amp;pl-&gt;state_mutex and &amp;phydev-&gt;lock must be<br /> consistent with this order.<br /> <br /> Problem impact<br /> ==============<br /> <br /> I think the kernel runs a serious deadlock risk if an existing<br /> phylink_resolve() thread, which results in a phy_config_inband() call,<br /> is concurrent with a phy_link_up() or phy_link_down() call, which will<br /> deadlock on &amp;pl-&gt;state_mutex in phylink_phy_change(). Practically<br /> speaking, the impact may be limited by the slow speed of the medium<br /> auto-negotiation protocol, which makes it unlikely for the current state<br /> to still be unresolved when a new one is detected, but I think the<br /> problem is there. Nonetheless, the problem was discovered using lockdep.<br /> <br /> Proposed solution<br /> =================<br /> <br /> Practically speaking, the phy_config_inband() requirement of having<br /> phydev-&gt;lock acquired must transfer to the caller (phylink is the only<br /> caller). There, it must bubble up until immediately before<br /> &amp;pl-&gt;state_mutex is acquired, for the cases where that takes place.<br /> <br /> Solution details, considerations, notes<br /> =======================================<br /> <br /> This is the phy_config_inband() call graph:<br /> <br /> sfp_upstream_ops :: connect_phy()<br /> |<br /> v<br /> phylink_sfp_connect_phy()<br /> |<br /> v<br /> phylink_sfp_config_phy()<br /> |<br /> | sfp_upstream_ops :: module_insert()<br /> | |<br /> | v<br /> | phylink_sfp_module_insert()<br /> | |<br /> | | sfp_upstream_ops :: module_start()<br /> | | |<br /> | | v<br /> | | phylink_sfp_module_start()<br /> | | |<br /> | v v<br /> | phylink_sfp_config_optical()<br /> phylink_start() | |<br /> | phylink_resume() v v<br /> | | phylink_sfp_set_config()<br /> | | |<br /> v v v<br /> phylink_mac_initial_config()<br /> | phylink_resolve()<br /> | | phylink_ethtool_ksettings_set()<br /> v v v<br /> phylink_major_config()<br /> |<br /> v<br /> phy_config_inband()<br /> <br /> phylink_major_config() caller #1, phylink_mac_initial_config(), does not<br /> acquire &amp;pl-&gt;state_mutex nor do its callers. It must acquire<br /> &amp;pl-&gt;phydev-&gt;lock prior to calling phylink_major_config().<br /> <br /> phylink_major_config() caller #2, phylink_resolve() acquires<br /> &amp;pl-&gt;state_mutex, thus also needs to acquire &amp;pl-&gt;phydev-&gt;lock.<br /> <br /> phylink_major_config() caller #3, phylink_ethtool_ksettings_set(), is<br /> completely uninteresting, because it only call<br /> ---truncated---

Vulnerable products and versions

CPE From Up to
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.14 (including) 6.16.8 (excluding)
cpe:2.3:o:linux:linux_kernel:6.17:rc1:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.17:rc2:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.17:rc3:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.17:rc4:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.17:rc5:*:*:*:*:*:*