Blob Blame History Raw
From: Edward Cree <ecree@solarflare.com>
Date: Tue, 1 Sep 2020 18:52:32 +0100
Subject: ethtool: fix error handling in ethtool_phys_id
Patch-mainline: v5.10-rc1
Git-commit: 2adc6edcaec09eea9275915e9632ff916fcd0785
References: git-fixes

If ops->set_phys_id() returned an error, previously we would only break
 out of the inner loop, which neither stopped the outer loop nor returned
 the error to the user (since 'rc' would be overwritten on the next pass
 through the loop).
Thus, rewrite it to use a single loop, so that the break does the right
 thing.  Use u64 for 'count' and 'i' to prevent overflow in case of
 (unreasonably) large values of id.data and n.

Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Michal Kubecek <mkubecek@suse.cz>

---
 net/core/ethtool.c | 25 ++++++++++---------------
 1 file changed, 10 insertions(+), 15 deletions(-)

--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -1897,23 +1897,18 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
 			id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT);
 	} else {
 		/* Driver expects to be called at twice the frequency in rc */
-		int n = rc * 2, i, interval = HZ / n;
+		int n = rc * 2, interval = HZ / n;
+		u64 count = n * id.data, i = 0;
 
-		/* Count down seconds */
 		do {
-			/* Count down iterations per second */
-			i = n;
-			do {
-				rtnl_lock();
-				rc = ops->set_phys_id(dev,
-				    (i & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
-				rtnl_unlock();
-				if (rc)
-					break;
-				schedule_timeout_interruptible(interval);
-			} while (!signal_pending(current) && --i != 0);
-		} while (!signal_pending(current) &&
-			 (id.data == 0 || --id.data != 0));
+			rtnl_lock();
+			rc = ops->set_phys_id(dev,
+				    (i++ & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
+			rtnl_unlock();
+			if (rc)
+				break;
+			schedule_timeout_interruptible(interval);
+		} while (!signal_pending(current) && (!id.data || i < count));
 	}
 
 	rtnl_lock();