]> git.baikalelectronics.ru Git - kernel.git/commitdiff
net: ipconfig: ic_dev can be NULL in ic_close_devs
authorVladimir Oltean <vladimir.oltean@nxp.com>
Mon, 22 Mar 2021 00:26:37 +0000 (02:26 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 22 Mar 2021 19:57:51 +0000 (12:57 -0700)
ic_close_dev contains a generalization of the logic to not close a
network interface if it's the host port for a DSA switch. This logic is
disguised behind an iteration through the lowers of ic_dev in
ic_close_dev.

When no interface for ipconfig can be found, ic_dev is NULL, and
ic_close_dev:
- dereferences a NULL pointer when assigning selected_dev
- would attempt to search through the lower interfaces of a NULL
  net_device pointer

So we should protect against that case.

The "lower_dev" iterator variable was shortened to "lower" in order to
keep the 80 character limit.

Fixes: 9c10fdff10e2 ("net: ipconfig: avoid use-after-free in ic_close_devs")
Fixes: 47694a2c6b5d ("Revert "net: ipv4: handle DSA enabled master network devices"")
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Tested-by: Heiko Thiery <heiko.thiery@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/ipconfig.c

index 47db1bfdaaa0a0c8e151ab927d87b50c49772a31..bc2f6ca971520e39d3d18299b80454cc949fd892 100644 (file)
@@ -309,7 +309,7 @@ have_carrier:
  */
 static void __init ic_close_devs(void)
 {
-       struct net_device *selected_dev = ic_dev->dev;
+       struct net_device *selected_dev = ic_dev ? ic_dev->dev : NULL;
        struct ic_device *d, *next;
        struct net_device *dev;
 
@@ -317,16 +317,18 @@ static void __init ic_close_devs(void)
        next = ic_first_dev;
        while ((d = next)) {
                bool bring_down = (d != ic_dev);
-               struct net_device *lower_dev;
+               struct net_device *lower;
                struct list_head *iter;
 
                next = d->next;
                dev = d->dev;
 
-               netdev_for_each_lower_dev(selected_dev, lower_dev, iter) {
-                       if (dev == lower_dev) {
-                               bring_down = false;
-                               break;
+               if (selected_dev) {
+                       netdev_for_each_lower_dev(selected_dev, lower, iter) {
+                               if (dev == lower) {
+                                       bring_down = false;
+                                       break;
+                               }
                        }
                }
                if (bring_down) {