[PATCH net] net: phy: reject attach while the PHY driver is in transition
From: Aleksei Sviridkin <hidden>
Date: 2026-09-14 20:42:04
Also in:
lkml
Subsystem:
ethernet phy library, networking drivers, the rest · Maintainers:
Andrew Lunn, Heiner Kallweit, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
phy_remove() clears phydev->drv as its last act; the driver core
clears d->driver only afterwards, in device_unbind_cleanup(). In that
window phy_attach_direct() skips the genphy substitution, because
d->driver is still set, and then dereferences the NULL phydev->drv in
phy_drv_supports_irq().
Refuse the attach there, before any reference on the driver is taken.
The function holds no lock over phydev->drv, and it cannot hold
device_lock across the attach: for a genphy-substituted PHY its error
path reaches device_release_driver() on the same device, which takes
that lock again. So this closes the case where the unbind is already
in flight; an unbind starting mid-attach still races.
Failing beats falling back to polling: phylink_bringup_phy()
dereferences phy->drv right after a successful attach, and a continued
attach would already hold the driver module reference that
phy_detach() drops only while d->driver is set, leaking it once the
unbind completes. -ENODEV is wrong: DSA takes it as permission to
look for the PHY on the switch's internal MDIO bus.
Fixes: 61c81872815f ("net: phy: phy_device: Prevent nullptr exceptions on ISR")
Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <redacted>
---
Notes:
Found by reading the unbind path, not from a crash report: phy_remove()
clears phydev->drv before the driver core clears d->driver, while
phy_attach_direct() keys its genphy substitution off d->driver.
Verified on an MT7981 board (mtk_eth_soc GMAC, "MediaTek MT7981 PHY" at
mdio-bus:00), 6.18.44, with a 200 ms msleep() added at the end of
phy_remove() to hold the window open. Two images, identical except for
this patch.
Without the patch, backgrounding
echo mdio-bus:00 > "/sys/bus/mdio_bus/drivers/MediaTek MT7981 PHY/unbind"
and immediately running "ip link set wan up" oopses on the first
attempt:
Unable to handle kernel access to user memory outside uaccess
routines at virtual address 0000000000000128
pc : phy_attach_direct+0x150/0x380
Call trace:
phy_attach_direct+0x150/0x380 (P)
mtk_open+0x38/0xb70
x0 is 0 and 0x128 is the offset of config_intr in struct phy_driver.
With the patch the same sequence fails the attach on the first attempt
instead, "wan: mtk_open: could not attach PHY: -16", and no oops is
logged. Binding the driver back and bringing the interface up afterwards
succeeds with the link up, so the early return leaves the phydev
reusable. An ordinary bring-up is unaffected, and with the driver left
unbound the genphy substitution still runs: "PHY [mdio-bus:00] driver
[Generic PHY]", link up.
drivers/net/phy/phy_device.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 94b2e85e00a3..044cefd9840b 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c@@ -1781,6 +1781,10 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, d->driver = &genphy_driver.mdiodrv.driver; phydev->is_genphy_driven = 1; + } else if (!phydev->drv) { + /* d->driver outlives phydev->drv on unbind, precedes it on bind */ + err = -EBUSY; + goto error_put_device; } if (!try_module_get(d->driver->owner)) {
--
2.53.0