From: Ben Hutchings Date: Fri, 16 Jan 2015 17:51:25 +0000 (+0000) Subject: sh_eth: Fix ethtool operation crash when net device is down X-Git-Tag: v3.19-rc6~29^2~3^2 X-Git-Url: http://git.cascardo.eti.br/?a=commitdiff_plain;h=4f9dce230b32eec45cec8c28cae61efdfa2f7d57;p=cascardo%2Flinux.git sh_eth: Fix ethtool operation crash when net device is down The driver connects and disconnects the PHY device whenever the net device is brought up and down. The ethtool get_settings, set_settings and nway_reset operations will dereference a null or dangling pointer if called while it is down. I think it would be preferable to keep the PHY connected, but there may be good reasons not to. As an immediate fix for this bug: - Set the phydev pointer to NULL after disconnecting the PHY - Change those three operations to return -ENODEV while the PHY is not connected Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 01dfae4fece0..6576243222af 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1827,6 +1827,9 @@ static int sh_eth_get_settings(struct net_device *ndev, unsigned long flags; int ret; + if (!mdp->phydev) + return -ENODEV; + spin_lock_irqsave(&mdp->lock, flags); ret = phy_ethtool_gset(mdp->phydev, ecmd); spin_unlock_irqrestore(&mdp->lock, flags); @@ -1841,6 +1844,9 @@ static int sh_eth_set_settings(struct net_device *ndev, unsigned long flags; int ret; + if (!mdp->phydev) + return -ENODEV; + spin_lock_irqsave(&mdp->lock, flags); /* disable tx and rx */ @@ -1875,6 +1881,9 @@ static int sh_eth_nway_reset(struct net_device *ndev) unsigned long flags; int ret; + if (!mdp->phydev) + return -ENODEV; + spin_lock_irqsave(&mdp->lock, flags); ret = phy_start_aneg(mdp->phydev); spin_unlock_irqrestore(&mdp->lock, flags); @@ -2184,6 +2193,7 @@ static int sh_eth_close(struct net_device *ndev) if (mdp->phydev) { phy_stop(mdp->phydev); phy_disconnect(mdp->phydev); + mdp->phydev = NULL; } free_irq(ndev->irq, ndev);