CVE-2025-39915

In the Linux kernel, the following vulnerability has been resolved:

net: phy: transfer phy_config_inband() locking responsibility to phylink

Problem description
===================

Lockdep reports a possible circular locking dependency (AB/BA) between
&pl->state_mutex and &phy->lock, as follows.

phylink_resolve() // acquires &pl->state_mutex
-> phylink_major_config()
   -> phy_config_inband() // acquires &pl->phydev->lock

whereas all the other call sites where &pl->state_mutex and
&pl->phydev->lock have the locking scheme reversed. Everywhere else,
&pl->phydev->lock is acquired at the top level, and &pl->state_mutex at
the lower level. A clear example is phylink_bringup_phy().

The outlier is the newly introduced phy_config_inband() and the existing
lock order is the correct one. To understand why it cannot be the other
way around, it is sufficient to consider phylink_phy_change(), phylink's
callback from the PHY device's phy->phy_link_change() virtual method,
invoked by the PHY state machine.

phy_link_up() and phy_link_down(), the (indirect) callers of
phylink_phy_change(), are called with &phydev->lock acquired.
Then phylink_phy_change() acquires its own &pl->state_mutex, to
serialize changes made to its pl->phy_state and pl->link_config.
So all other instances of &pl->state_mutex and &phydev->lock must be
consistent with this order.

Problem impact
==============

I think the kernel runs a serious deadlock risk if an existing
phylink_resolve() thread, which results in a phy_config_inband() call,
is concurrent with a phy_link_up() or phy_link_down() call, which will
deadlock on &pl->state_mutex in phylink_phy_change(). Practically
speaking, the impact may be limited by the slow speed of the medium
auto-negotiation protocol, which makes it unlikely for the current state
to still be unresolved when a new one is detected, but I think the
problem is there. Nonetheless, the problem was discovered using lockdep.

Proposed solution
=================

Practically speaking, the phy_config_inband() requirement of having
phydev->lock acquired must transfer to the caller (phylink is the only
caller). There, it must bubble up until immediately before
&pl->state_mutex is acquired, for the cases where that takes place.

Solution details, considerations, notes
=======================================

This is the phy_config_inband() call graph:

                          sfp_upstream_ops :: connect_phy()
                          |
                          v
                          phylink_sfp_connect_phy()
                          |
                          v
                          phylink_sfp_config_phy()
                          |
                          |   sfp_upstream_ops :: module_insert()
                          |   |
                          |   v
                          |   phylink_sfp_module_insert()
                          |   |
                          |   |   sfp_upstream_ops :: module_start()
                          |   |   |
                          |   |   v
                          |   |   phylink_sfp_module_start()
                          |   |   |
                          |   v   v
                          |   phylink_sfp_config_optical()
 phylink_start()          |   |
   |   phylink_resume()   v   v
   |   |  phylink_sfp_set_config()
   |   |  |
   v   v  v
 phylink_mac_initial_config()
   |   phylink_resolve()
   |   |  phylink_ethtool_ksettings_set()
   v   v  v
   phylink_major_config()
            |
            v
    phy_config_inband()

phylink_major_config() caller #1, phylink_mac_initial_config(), does not
acquire &pl->state_mutex nor do its callers. It must acquire
&pl->phydev->lock prior to calling phylink_major_config().

phylink_major_config() caller #2, phylink_resolve() acquires
&pl->state_mutex, thus also needs to acquire &pl->phydev->lock.

phylink_major_config() caller #3, phylink_ethtool_ksettings_set(), is
completely uninteresting, because it only call
---truncated---
ProviderTypeBase ScoreAtk. VectorAtk. ComplexityPriv. RequiredVector
NISTNIST
UNKNOWN
---
LinuxCNA
---
---
Awaiting analysis
This vulnerability is currently awaiting analysis.
Base Score
CVSS 3.x
EPSS Score
Percentile: 6%
Debian logo
Debian Releases
Debian Product
Codename
linux
bullseye
5.10.223-1
not-affected
trixie
6.12.57-1
not-affected
bookworm
6.1.148-1
not-affected
bullseye (security)
5.10.244-1
fixed
bookworm (security)
6.1.158-1
fixed
trixie (security)
6.12.48-1
fixed
forky
6.16.12-2
fixed
sid
6.17.8-1
fixed
Ubuntu logo
Ubuntu Releases
Ubuntu Product
Codename
linux
plucky
needs-triage
noble
needs-triage
jammy
needs-triage
focal
needs-triage
bionic
needs-triage
xenial
needs-triage
trusty
needs-triage
linux-hwe
plucky
dne
noble
dne
jammy
dne
bionic
ignored
xenial
needs-triage
linux-hwe-5.4
plucky
dne
noble
dne
jammy
dne
bionic
needs-triage
linux-hwe-5.8
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-hwe-5.11
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-hwe-5.13
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-hwe-5.15
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-hwe-5.19
plucky
dne
noble
dne
jammy
ignored
linux-hwe-6.2
plucky
dne
noble
dne
jammy
ignored
linux-hwe-6.5
plucky
dne
noble
dne
jammy
ignored
linux-hwe-6.8
plucky
dne
noble
dne
jammy
needs-triage
linux-hwe-6.11
plucky
dne
noble
ignored
jammy
dne
linux-hwe-6.14
plucky
dne
noble
needs-triage
jammy
dne
linux-hwe-edge
plucky
dne
noble
dne
jammy
dne
bionic
ignored
xenial
ignored
linux-lts-xenial
plucky
dne
noble
dne
jammy
dne
trusty
needs-triage
linux-kvm
plucky
dne
noble
dne
jammy
needs-triage
focal
needs-triage
bionic
needs-triage
xenial
needs-triage
linux-allwinner-5.19
plucky
dne
noble
dne
jammy
ignored
linux-aws
plucky
needs-triage
noble
needs-triage
jammy
needs-triage
focal
needs-triage
bionic
needs-triage
xenial
needs-triage
trusty
needs-triage
linux-aws-5.0
plucky
dne
noble
dne
jammy
dne
bionic
ignored
linux-aws-5.3
plucky
dne
noble
dne
jammy
dne
bionic
ignored
linux-aws-5.4
plucky
dne
noble
dne
jammy
dne
bionic
needs-triage
linux-aws-5.8
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-aws-5.11
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-aws-5.13
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-aws-5.15
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-aws-5.19
plucky
dne
noble
dne
jammy
ignored
linux-aws-6.2
plucky
dne
noble
dne
jammy
ignored
linux-aws-6.5
plucky
dne
noble
dne
jammy
ignored
linux-aws-6.8
plucky
dne
noble
dne
jammy
needs-triage
linux-aws-6.14
plucky
dne
noble
needs-triage
jammy
dne
linux-aws-hwe
plucky
dne
noble
dne
jammy
dne
xenial
needs-triage
linux-azure
plucky
needs-triage
noble
needs-triage
jammy
needs-triage
focal
needs-triage
bionic
ignored
xenial
needs-triage
trusty
needs-triage
linux-azure-4.15
plucky
dne
noble
dne
jammy
dne
bionic
needs-triage
linux-azure-5.3
plucky
dne
noble
dne
jammy
dne
bionic
ignored
linux-azure-5.4
plucky
dne
noble
dne
jammy
dne
bionic
needs-triage
linux-azure-5.8
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-azure-5.11
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-azure-5.13
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-azure-5.15
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-azure-5.19
plucky
dne
noble
dne
jammy
ignored
linux-azure-6.2
plucky
dne
noble
dne
jammy
ignored
linux-azure-6.5
plucky
dne
noble
dne
jammy
ignored
linux-azure-6.8
plucky
dne
noble
dne
jammy
needs-triage
linux-azure-6.11
plucky
dne
noble
ignored
jammy
dne
linux-azure-fde
plucky
needs-triage
noble
dne
jammy
needs-triage
focal
ignored
linux-azure-fde-5.15
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-azure-fde-5.19
plucky
dne
noble
dne
jammy
ignored
linux-azure-fde-6.2
plucky
dne
noble
dne
jammy
ignored
linux-azure-nvidia
plucky
dne
noble
needs-triage
jammy
dne
linux-bluefield
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-azure-edge
plucky
dne
noble
dne
jammy
dne
bionic
ignored
linux-fips
plucky
dne
noble
dne
jammy
needs-triage
focal
needs-triage
bionic
needs-triage
xenial
needs-triage
linux-aws-fips
plucky
dne
noble
dne
jammy
needs-triage
focal
needs-triage
bionic
needs-triage
linux-azure-fips
plucky
dne
noble
dne
jammy
needs-triage
focal
needs-triage
bionic
needs-triage
linux-gcp-fips
plucky
dne
noble
dne
jammy
needs-triage
focal
needs-triage
bionic
needs-triage
linux-gcp
plucky
needs-triage
noble
needs-triage
jammy
needs-triage
focal
needs-triage
bionic
ignored
xenial
needs-triage
linux-gcp-4.15
plucky
dne
noble
dne
jammy
dne
bionic
needs-triage
linux-gcp-5.3
plucky
dne
noble
dne
jammy
dne
bionic
ignored
linux-gcp-5.4
plucky
dne
noble
dne
jammy
dne
bionic
needs-triage
linux-gcp-5.8
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-gcp-5.11
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-gcp-5.13
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-gcp-5.15
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-gcp-5.19
plucky
dne
noble
dne
jammy
ignored
linux-gcp-6.2
plucky
dne
noble
dne
jammy
ignored
linux-gcp-6.5
plucky
dne
noble
dne
jammy
ignored
linux-gcp-6.8
plucky
dne
noble
dne
jammy
needs-triage
linux-gcp-6.11
plucky
dne
noble
ignored
jammy
dne
linux-gcp-6.14
plucky
dne
noble
needs-triage
jammy
dne
linux-gke
plucky
dne
noble
needs-triage
jammy
needs-triage
focal
ignored
linux-gke-4.15
plucky
dne
noble
dne
jammy
dne
bionic
ignored
linux-gke-5.4
plucky
dne
noble
dne
jammy
dne
bionic
ignored
linux-gke-5.15
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-gkeop
plucky
dne
noble
needs-triage
jammy
needs-triage
focal
ignored
linux-gkeop-5.4
plucky
dne
noble
dne
jammy
dne
bionic
ignored
linux-gkeop-5.15
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-ibm
plucky
dne
noble
needs-triage
jammy
needs-triage
focal
needs-triage
linux-ibm-5.4
plucky
dne
noble
dne
jammy
dne
bionic
needs-triage
linux-ibm-5.15
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-ibm-6.8
plucky
dne
noble
dne
jammy
needs-triage
linux-intel-5.13
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-intel-iotg
plucky
dne
noble
dne
jammy
needs-triage
linux-intel-iotg-5.15
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-iot
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-intel-iot-realtime
plucky
dne
noble
dne
jammy
needs-triage
linux-lowlatency
plucky
dne
noble
needs-triage
jammy
needs-triage
linux-lowlatency-hwe-5.15
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-lowlatency-hwe-5.19
plucky
dne
noble
dne
jammy
ignored
linux-lowlatency-hwe-6.2
plucky
dne
noble
dne
jammy
ignored
linux-lowlatency-hwe-6.5
plucky
dne
noble
dne
jammy
ignored
linux-lowlatency-hwe-6.8
plucky
dne
noble
dne
jammy
needs-triage
linux-lowlatency-hwe-6.11
plucky
dne
noble
ignored
jammy
dne
linux-nvidia
plucky
dne
noble
needs-triage
jammy
needs-triage
linux-nvidia-6.2
plucky
dne
noble
dne
jammy
ignored
linux-nvidia-6.5
plucky
dne
noble
dne
jammy
ignored
linux-nvidia-6.8
plucky
dne
noble
dne
jammy
needs-triage
linux-nvidia-6.11
plucky
dne
noble
needs-triage
jammy
dne
linux-nvidia-lowlatency
plucky
dne
noble
needs-triage
jammy
dne
linux-nvidia-tegra
plucky
dne
noble
needs-triage
jammy
needs-triage
linux-nvidia-tegra-5.15
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-nvidia-tegra-igx
plucky
dne
noble
dne
jammy
needs-triage
linux-oracle
plucky
needs-triage
noble
needs-triage
jammy
needs-triage
focal
needs-triage
bionic
needs-triage
xenial
needs-triage
linux-oracle-5.0
plucky
dne
noble
dne
jammy
dne
bionic
ignored
linux-oracle-5.3
plucky
dne
noble
dne
jammy
dne
bionic
ignored
linux-oracle-5.4
plucky
dne
noble
dne
jammy
dne
bionic
needs-triage
linux-oracle-5.8
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-oracle-5.11
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-oracle-5.13
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-oracle-5.15
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-oracle-6.5
plucky
dne
noble
dne
jammy
ignored
linux-oracle-6.8
plucky
dne
noble
dne
jammy
needs-triage
linux-oracle-6.14
plucky
dne
noble
needs-triage
jammy
dne
linux-oem
plucky
dne
noble
dne
jammy
dne
bionic
ignored
linux-oem-5.6
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-oem-5.10
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-oem-5.13
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-oem-5.14
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-oem-5.17
plucky
dne
noble
dne
jammy
ignored
linux-oem-6.0
plucky
dne
noble
dne
jammy
ignored
linux-oem-6.1
plucky
dne
noble
dne
jammy
ignored
linux-oem-6.5
plucky
dne
noble
dne
jammy
ignored
linux-oem-6.8
plucky
dne
noble
needs-triage
jammy
dne
linux-oem-6.11
plucky
dne
noble
needs-triage
jammy
dne
linux-oem-6.14
plucky
dne
noble
needs-triage
jammy
dne
linux-raspi
plucky
needs-triage
noble
needs-triage
jammy
needs-triage
focal
needs-triage
linux-raspi2
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-raspi-5.4
plucky
dne
noble
dne
jammy
dne
bionic
needs-triage
linux-raspi-realtime
plucky
dne
noble
needs-triage
jammy
dne
linux-realtime
plucky
needs-triage
noble
needs-triage
jammy
needs-triage
linux-realtime-6.8
plucky
dne
noble
dne
jammy
needs-triage
linux-realtime-6.14
plucky
dne
noble
needs-triage
jammy
dne
linux-riscv
plucky
needs-triage
noble
ignored
jammy
ignored
focal
ignored
linux-riscv-5.8
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-riscv-5.11
plucky
dne
noble
dne
jammy
dne
focal
ignored
linux-riscv-5.15
plucky
dne
noble
dne
jammy
dne
focal
needs-triage
linux-riscv-5.19
plucky
dne
noble
dne
jammy
ignored
linux-riscv-6.5
plucky
dne
noble
dne
jammy
ignored
linux-riscv-6.8
plucky
dne
noble
dne
jammy
needs-triage
linux-riscv-6.14
plucky
dne
noble
needs-triage
jammy
dne
linux-starfive-5.19
plucky
dne
noble
dne
jammy
ignored
linux-starfive-6.2
plucky
dne
noble
dne
jammy
ignored
linux-starfive-6.5
plucky
dne
noble
dne
jammy
ignored
linux-xilinx-zynqmp
plucky
dne
noble
dne
jammy
needs-triage
focal
needs-triage