All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net 0/2] net: phy: Fix PHY unbind crash
@ 2017-02-18  0:07 Florian Fainelli
  2017-02-18  0:07 ` [PATCH net 1/2] " Florian Fainelli
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Florian Fainelli @ 2017-02-18  0:07 UTC (permalink / raw)
  To: netdev; +Cc: davem, andrew, rmk+kernel, Florian Fainelli

Hi David,

This fixes crashes when the PHY driver is no longer bound to the device.

There is still a fair amount of work to be done to get the unbind -> bind
sequent to result in a functional state, but that will be net-next material.

These two problems existed for as long as PHYLIB as been around.

Thanks!

Florian Fainelli (2):
  net: phy: Fix PHY unbind crash
  net: phy: Check phydev->drv

 drivers/net/phy/phy.c        | 26 ++++++++++++++++++++++----
 drivers/net/phy/phy_device.c |  8 +++++---
 include/linux/phy.h          |  3 +++
 3 files changed, 30 insertions(+), 7 deletions(-)

-- 
2.9.3

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH net 1/2] net: phy: Fix PHY unbind crash
  2017-02-18  0:07 [PATCH net 0/2] net: phy: Fix PHY unbind crash Florian Fainelli
@ 2017-02-18  0:07 ` Florian Fainelli
  2017-02-18  0:07 ` [PATCH net 2/2] net: phy: Check phydev->drv Florian Fainelli
  2017-02-20 15:15 ` [PATCH net 0/2] net: phy: Fix PHY unbind crash David Miller
  2 siblings, 0 replies; 4+ messages in thread
From: Florian Fainelli @ 2017-02-18  0:07 UTC (permalink / raw)
  To: netdev; +Cc: davem, andrew, rmk+kernel, Florian Fainelli

The PHY library does not deal very well with bind and unbind events. The first
thing we would see is that we were not properly canceling the PHY state machine
workqueue, so we would be crashing while dereferencing phydev->drv since there
is no driver attached anymore.

Suggested-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/net/phy/phy_device.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 8c8e15b8739d..7f9319586b7e 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1784,6 +1784,8 @@ static int phy_remove(struct device *dev)
 {
 	struct phy_device *phydev = to_phy_device(dev);
 
+	cancel_delayed_work_sync(&phydev->state_queue);
+
 	mutex_lock(&phydev->lock);
 	phydev->state = PHY_DOWN;
 	mutex_unlock(&phydev->lock);
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH net 2/2] net: phy: Check phydev->drv
  2017-02-18  0:07 [PATCH net 0/2] net: phy: Fix PHY unbind crash Florian Fainelli
  2017-02-18  0:07 ` [PATCH net 1/2] " Florian Fainelli
@ 2017-02-18  0:07 ` Florian Fainelli
  2017-02-20 15:15 ` [PATCH net 0/2] net: phy: Fix PHY unbind crash David Miller
  2 siblings, 0 replies; 4+ messages in thread
From: Florian Fainelli @ 2017-02-18  0:07 UTC (permalink / raw)
  To: netdev; +Cc: davem, andrew, rmk+kernel, Florian Fainelli

There are number of function calls, originating from user-space,
typically through the Ethernet driver that can make us crash by
dereferencing phydev->drv which will be NULL once we unbind the driver
from the PHY.

There are still functional issues that prevent an unbind then rebind to
work, but these will be addressed separately.

Suggested-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/net/phy/phy.c        | 26 ++++++++++++++++++++++----
 drivers/net/phy/phy_device.c |  6 +++---
 include/linux/phy.h          |  3 +++
 3 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 7cc1b7dcfe05..d6f7838455dd 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -580,7 +580,7 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
 		return 0;
 
 	case SIOCSHWTSTAMP:
-		if (phydev->drv->hwtstamp)
+		if (phydev->drv && phydev->drv->hwtstamp)
 			return phydev->drv->hwtstamp(phydev, ifr);
 		/* fall through */
 
@@ -603,6 +603,9 @@ int phy_start_aneg(struct phy_device *phydev)
 {
 	int err;
 
+	if (!phydev->drv)
+		return -EIO;
+
 	mutex_lock(&phydev->lock);
 
 	if (AUTONEG_DISABLE == phydev->autoneg)
@@ -975,7 +978,7 @@ void phy_state_machine(struct work_struct *work)
 
 	old_state = phydev->state;
 
-	if (phydev->drv->link_change_notify)
+	if (phydev->drv && phydev->drv->link_change_notify)
 		phydev->drv->link_change_notify(phydev);
 
 	switch (phydev->state) {
@@ -1286,6 +1289,9 @@ EXPORT_SYMBOL(phy_write_mmd_indirect);
  */
 int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
 {
+	if (!phydev->drv)
+		return -EIO;
+
 	/* According to 802.3az,the EEE is supported only in full duplex-mode.
 	 * Also EEE feature is active when core is operating with MII, GMII
 	 * or RGMII (all kinds). Internal PHYs are also allowed to proceed and
@@ -1363,6 +1369,9 @@ EXPORT_SYMBOL(phy_init_eee);
  */
 int phy_get_eee_err(struct phy_device *phydev)
 {
+	if (!phydev->drv)
+		return -EIO;
+
 	return phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_WK_ERR, MDIO_MMD_PCS);
 }
 EXPORT_SYMBOL(phy_get_eee_err);
@@ -1379,6 +1388,9 @@ int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data)
 {
 	int val;
 
+	if (!phydev->drv)
+		return -EIO;
+
 	/* Get Supported EEE */
 	val = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE, MDIO_MMD_PCS);
 	if (val < 0)
@@ -1412,6 +1424,9 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data)
 {
 	int val = ethtool_adv_to_mmd_eee_adv_t(data->advertised);
 
+	if (!phydev->drv)
+		return -EIO;
+
 	/* Mask prohibited EEE modes */
 	val &= ~phydev->eee_broken_modes;
 
@@ -1423,7 +1438,7 @@ EXPORT_SYMBOL(phy_ethtool_set_eee);
 
 int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
 {
-	if (phydev->drv->set_wol)
+	if (phydev->drv && phydev->drv->set_wol)
 		return phydev->drv->set_wol(phydev, wol);
 
 	return -EOPNOTSUPP;
@@ -1432,7 +1447,7 @@ EXPORT_SYMBOL(phy_ethtool_set_wol);
 
 void phy_ethtool_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
 {
-	if (phydev->drv->get_wol)
+	if (phydev->drv && phydev->drv->get_wol)
 		phydev->drv->get_wol(phydev, wol);
 }
 EXPORT_SYMBOL(phy_ethtool_get_wol);
@@ -1468,6 +1483,9 @@ int phy_ethtool_nway_reset(struct net_device *ndev)
 	if (!phydev)
 		return -ENODEV;
 
+	if (!phydev->drv)
+		return -EIO;
+
 	return genphy_restart_aneg(phydev);
 }
 EXPORT_SYMBOL(phy_ethtool_nway_reset);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 7f9319586b7e..daec6555f3b1 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1094,7 +1094,7 @@ int phy_suspend(struct phy_device *phydev)
 	if (wol.wolopts)
 		return -EBUSY;
 
-	if (phydrv->suspend)
+	if (phydev->drv && phydrv->suspend)
 		ret = phydrv->suspend(phydev);
 
 	if (ret)
@@ -1111,7 +1111,7 @@ int phy_resume(struct phy_device *phydev)
 	struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
 	int ret = 0;
 
-	if (phydrv->resume)
+	if (phydev->drv && phydrv->resume)
 		ret = phydrv->resume(phydev);
 
 	if (ret)
@@ -1790,7 +1790,7 @@ static int phy_remove(struct device *dev)
 	phydev->state = PHY_DOWN;
 	mutex_unlock(&phydev->lock);
 
-	if (phydev->drv->remove)
+	if (phydev->drv && phydev->drv->remove)
 		phydev->drv->remove(phydev);
 	phydev->drv = NULL;
 
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 7fc1105605bf..231e07bb0d76 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -802,6 +802,9 @@ int phy_stop_interrupts(struct phy_device *phydev);
 
 static inline int phy_read_status(struct phy_device *phydev)
 {
+	if (!phydev->drv)
+		return -EIO;
+
 	return phydev->drv->read_status(phydev);
 }
 
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH net 0/2] net: phy: Fix PHY unbind crash
  2017-02-18  0:07 [PATCH net 0/2] net: phy: Fix PHY unbind crash Florian Fainelli
  2017-02-18  0:07 ` [PATCH net 1/2] " Florian Fainelli
  2017-02-18  0:07 ` [PATCH net 2/2] net: phy: Check phydev->drv Florian Fainelli
@ 2017-02-20 15:15 ` David Miller
  2 siblings, 0 replies; 4+ messages in thread
From: David Miller @ 2017-02-20 15:15 UTC (permalink / raw)
  To: f.fainelli; +Cc: netdev, andrew, rmk+kernel

From: Florian Fainelli <f.fainelli@gmail.com>
Date: Fri, 17 Feb 2017 16:07:32 -0800

> This fixes crashes when the PHY driver is no longer bound to the device.
> 
> There is still a fair amount of work to be done to get the unbind -> bind
> sequent to result in a functional state, but that will be net-next material.
> 
> These two problems existed for as long as PHYLIB as been around.

Series applied, thanks.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-02-20 15:16 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-18  0:07 [PATCH net 0/2] net: phy: Fix PHY unbind crash Florian Fainelli
2017-02-18  0:07 ` [PATCH net 1/2] " Florian Fainelli
2017-02-18  0:07 ` [PATCH net 2/2] net: phy: Check phydev->drv Florian Fainelli
2017-02-20 15:15 ` [PATCH net 0/2] net: phy: Fix PHY unbind crash David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.