Skip to contentSkip to conversation

: rtnl_link: fix use-after-free

NET Applied Patrick McHardy 2 participants 2 messages Jan 20, 2008 – Jan 21, 2008

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

commit 6e470bd53fb50632fe1878bb74bb8531a21b6731

Author: Patrick McHardy <[email protected]>
Date:   Sun Jan 20 18:19:15 2008 +0100

[NET]: rtnl_link: fix use-after-free

When unregistering the rtnl_link_ops, all existing devices using the ops are destroyed. With nested devices this may lead to a use-after-free despite the use of for_each_netdev_safe() in case the upper device is next in the device list and is destroyed by the NETDEV_UNREGISTER notifier.

The easy fix is to restart scanning the device list after removing a device. Alternatively we could add new devices to the front of the list to avoid having dependant devices follow the device they depend on. A third option would be to only restart scanning if dev->iflink of the next device matches dev->ifindex of the current one. For now this seems like the safest solution.

With this patch, the veth rtnl_link_ops unregistration can use rtnl_link_unregister() directly since it now also handles destruction of multiple devices at once.

drivers/net/veth.c +1 -13
index 43af9e9..3f67a29 100644
@@ -459,19 +459,7 @@ static __init int veth_init(void)
 
 static __exit void veth_exit(void)
 {
-	struct veth_priv *priv, *next;
-
-	rtnl_lock();
-	/*
-	 * cannot trust __rtnl_link_unregister() to unregister all
-	 * devices, as each ->dellink call will remove two devices
-	 * from the list at once.
-	 */
-	list_for_each_entry_safe(priv, next, &veth_list, list)
-		veth_dellink(priv->dev);
-
-	__rtnl_link_unregister(&veth_link_ops);
-	rtnl_unlock();
+	rtnl_link_unregister(&veth_link_ops);
 }
 
 module_init(veth_init);
net/core/rtnetlink.c +4 -1
index e1ba26f..fed95a3 100644
@@ -308,9 +308,12 @@ void __rtnl_link_unregister(struct rtnl_link_ops *ops)
 	struct net *net;
 
 	for_each_net(net) {
+restart:
 		for_each_netdev_safe(net, dev, n) {
-			if (dev->rtnl_link_ops == ops)
+			if (dev->rtnl_link_ops == ops) {
 				ops->dellink(dev);
+				goto restart;
+			}
 		}
 	}
 	list_del(&ops->list);
maintainer Applied
#1 lore raw

From: Patrick McHardy <[email protected]>
Date: Sun, 20 Jan 2008 18:21:27 +0100

Quoted 19 lines

commit 6e470bd53fb50632fe1878bb74bb8531a21b6731

Author: Patrick McHardy <[email protected]>
Date:   Sun Jan 20 18:19:15 2008 +0100

[NET]: rtnl_link: fix use-after-free

When unregistering the rtnl_link_ops, all existing devices using the ops are destroyed. With nested devices this may lead to a use-after-free despite the use of for_each_netdev_safe() in case the upper device is next in the device list and is destroyed by the NETDEV_UNREGISTER notifier.

The easy fix is to restart scanning the device list after removing a device. Alternatively we could add new devices to the front of the list to avoid having dependant devices follow the device they depend on. A third option would be to only restart scanning if dev->iflink of the next device matches dev->ifindex of the current one. For now this seems like the safest solution.

Quoted 5 lines

With this patch, the veth rtnl_link_ops unregistration can use rtnl_link_unregister() directly since it now also handles destruction of multiple devices at once.

Applied, thanks.