diff mbox series

[1/2] net: phy: Check phydev->drv before dereferencing it

Message ID 20231126141046.3505343-2-claudiu.beznea@tuxon.dev (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series net: macb: Fixes for macb driver | expand

Checks

Context Check Description
netdev/series_format warning Target tree name not specified in the subject
netdev/codegen success Generated files up to date
netdev/tree_selection success Guessed tree name to be net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1115 this patch: 1115
netdev/cc_maintainers success CCed 8 of 9 maintainers
netdev/build_clang success Errors and warnings before: 1142 this patch: 1142
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 1142 this patch: 1142
netdev/checkpatch warning WARNING: Please use correct Fixes: style 'Fixes: <12 chars of sha1> ("<title line>")' - ie: 'Fixes: 00db8189d984 ("This patch adds a PHY Abstraction Layer to the Linux Kernel, enabling ethernet drivers to remain as ignorant as is reasonable of the connected PHY's design and operation details.")'
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Claudiu Nov. 26, 2023, 2:10 p.m. UTC
The macb driver calls mdiobus_unregister() and mdiobus_free() in its remove
function before calling unregister_netdev(). unregister_netdev() calls the
driver-specific struct net_device_ops::ndo_stop function (macb_close()),
and macb_close() calls phylink_disconnect_phy(). This, in turn, will call:

phy_disconnect() ->
  phy_free_interrupt() ->
    phy_disable_interrupts() ->
      phy_config_interrupt()

which dereference phydev->drv, which was already freed by:
mdiobus_unregister() ->
  phy_mdio_device_remove() ->
    device_del() ->
      bus_remove_device() ->
        device_release_driver_internal() ->
          phy_remove()

from macb_close().

Although the sequence in the macb driver is not correct, check phydev->drv      
before dereferencing it in phy_config_interrupt() to avoid scenarios
like the one described.

Fixes: 00db8189d984 ("This patch adds a PHY Abstraction Layer to the Linux Kernel")
Signed-off-by: Claudiu Beznea <claudiu.beznea@tuxon.dev>
---
 drivers/net/phy/phy.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Russell King (Oracle) Nov. 26, 2023, 3:53 p.m. UTC | #1
On Sun, Nov 26, 2023 at 04:10:45PM +0200, Claudiu Beznea wrote:
> The macb driver calls mdiobus_unregister() and mdiobus_free() in its remove
> function before calling unregister_netdev(). unregister_netdev() calls the
> driver-specific struct net_device_ops::ndo_stop function (macb_close()),
> and macb_close() calls phylink_disconnect_phy(). This, in turn, will call:
> 
> phy_disconnect() ->
>   phy_free_interrupt() ->
>     phy_disable_interrupts() ->
>       phy_config_interrupt()
> 
> which dereference phydev->drv, which was already freed by:
> mdiobus_unregister() ->
>   phy_mdio_device_remove() ->
>     device_del() ->
>       bus_remove_device() ->
>         device_release_driver_internal() ->
>           phy_remove()
> 
> from macb_close().
> 
> Although the sequence in the macb driver is not correct, check phydev->drv      
> before dereferencing it in phy_config_interrupt() to avoid scenarios
> like the one described.

I don't know why I've ended up with two copies of this series, but as
said in the other posting of this patch (where details of why can be
found)... NAK.
diff mbox series

Patch

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index a5fa077650e8..dd98a4b3ef81 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -165,7 +165,7 @@  EXPORT_SYMBOL_GPL(phy_get_rate_matching);
 static int phy_config_interrupt(struct phy_device *phydev, bool interrupts)
 {
 	phydev->interrupts = interrupts ? 1 : 0;
-	if (phydev->drv->config_intr)
+	if (phydev->drv && phydev->drv->config_intr)
 		return phydev->drv->config_intr(phydev);
 
 	return 0;