From: netdev-bot+sashiko@kernel.org
To: f@lex.la
Cc: netdev@vger.kernel.org, andrew@lunn.ch, hkallweit1@gmail.com,
linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, linux-kernel@vger.kernel.org
Subject: Re: [PATCH net] net: phy: reject attach while the PHY driver is in transition
Date: Thu, 17 Sep 2026 11:43:14 +0000 [thread overview]
Message-ID: <178964539462.22033.78864518608969481@kernel.org> (raw)
In-Reply-To: <20260914204200.2743251-1-f@lex.la>
Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider:
Critical: 0 · High: 1 · Medium: 1 · Low: 0
- [High] Incomplete fix / residual TOCTOU: the new `else if
(!phydev->drv)` test in phy_attach_direct()…
- [Medium] Module reference imbalance survives the residual unbind window
that this patch claims to close.
--
net: phy: reject attach while the PHY driver is in transition
The patch adds an early -EBUSY return in phy_attach_direct() when
d->driver is still set but phydev->drv has already been cleared, which is
the window between phy_remove() and device_unbind_cleanup(). The intent is
to avoid dereferencing a NULL phydev->drv in phy_drv_supports_irq() and to
avoid leaking the PHY driver module reference.
> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
> index 94b2e85e00a37..044cefd9840bb 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;
> }
[Severity: High]
Is this check able to prevent the oops quoted in the changelog, given that
it samples phydev->drv once and the dereference happens much later in the
same function?
The commit message says the function holds no lock over phydev->drv, and
get_device(d) only pins the device object, so the unbind can land right
after the test:
CPU0 phy_attach_direct()
} else if (!phydev->drv) { /* passes, drv still set */
CPU1 phy_remove()
phydev->drv = NULL;
CPU0 continues in phy_attach_direct()
if (!phy_drv_supports_irq(phydev->drv) && phy_interrupt_is_valid(phydev))
and phy_drv_supports_irq() has no NULL test:
static bool phy_drv_supports_irq(const struct phy_driver *phydrv)
{
return phydrv->config_intr && phydrv->handle_interrupt;
}
That is the same faulting access described in the notes (offset 0x128 being
phy_driver::config_intr), and it is the dereference named by the Fixes: tag.
The changelog does acknowledge "an unbind starting mid-attach still races",
but with a Fixes: tag attached, would a stable backporter reasonably
conclude the crash signature is gone when it is still reachable?
Should the single unguarded use be made NULL-tolerant instead, the way
phy_init_hw() already is, rather than adding a sampled check far away from
it?
There is a second dereference in the same window. If
device_unbind_cleanup() also runs, dev->driver becomes NULL:
drivers/base/dd.c:device_unbind_cleanup() {
...
device_set_driver(dev, NULL);
...
}
and the statement immediately after the new check re-reads it:
if (!try_module_get(d->driver->owner)) {
Can that path fault too, since the new test looks at phydev->drv but this
line dereferences d->driver?
Finally, phylink_bringup_phy() dereferences phy->drv right after a
successful attach. If the unbind stores land just as phy_attach_direct()
returns 0, does that caller hit a NULL phy->drv as well?
[Severity: Medium]
The changelog gives the module reference leak as a reason to fail here:
"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"
Does that leak remain reachable in the window the patch leaves open?
phy_attach_direct() charges the reference keyed on the mutable field, right
after the new check:
if (!try_module_get(d->driver->owner)) {
and phy_detach() re-reads the same field at release time instead of the
module that was charged:
if (phydev->mdio.dev.driver)
module_put(phydev->mdio.dev.driver->owner);
So for the sequence [new check passes] -> [try_module_get(A->owner)] ->
[phy_remove() clears phydev->drv, device_unbind_cleanup() clears
dev->driver] -> [attach fails later, for example on the phydev->attached_dev
"PHY already attached" path, phy_link_topo_add_phy() or phy_init_hw(), or
the netdev is brought down afterwards], phy_detach() sees a NULL
d->driver and skips the module_put(). Does module A then stay pinned
forever?
There is also a mismatched-module variant: if the mdio device is bound to a
different PHY driver B via sysfs before phy_detach() runs, phy_detach()
would call module_put(B->owner) for a reference it never took. Can that
underflow B's refcount and allow unloading a module still in use?
Would recording the module pinned at attach time, rather than sampling
d->driver twice, close both cases?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260914204200.2743251-1-f%40lex.la
next prev parent reply other threads:[~2026-09-17 11:43 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-14 20:42 Aleksei Sviridkin
2026-09-17 11:43 ` netdev-bot+sashiko [this message]
2026-09-17 12:00 ` Maxime Chevallier
2026-09-17 18:33 ` Aleksei Sviridkin
2026-09-17 20:30 ` Maxime Chevallier
2026-09-17 21:04 ` Aleksei Sviridkin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=178964539462.22033.78864518608969481@kernel.org \
--to=netdev-bot+sashiko@kernel.org \
--cc=andrew@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=f@lex.la \
--cc=hkallweit1@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®