Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62e841cd authored by Ben Hutchings's avatar Ben Hutchings Committed by Greg Kroah-Hartman
Browse files

sh_eth: Fix ethtool operation crash when net device is down



commit 4f9dce230b32eec45cec8c28cae61efdfa2f7d57 upstream.

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: default avatarBen Hutchings <ben.hutchings@codethink.co.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarAmit Pundir <amit.pundir@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0c59f879
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1832,6 +1832,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);
@@ -1846,6 +1849,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 */
@@ -1880,6 +1886,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);
@@ -2189,6 +2198,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);