summary refs log tree commit diff
path: root/drivers/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-01-20 17:25:14 -0800
committerDavid S. Miller <davem@davemloft.net>2008-01-20 20:31:45 -0800
commit68365458a4252fa993b91a00f7a0b18fed399f0d (patch)
tree824b1f32ba3b955c018626127602c365f986ccfc /drivers/net
parentd4782c323d10d3698b71b6a6b3c7bdad33824658 (diff)
downloadlinux-68365458a4252fa993b91a00f7a0b18fed399f0d.tar.gz
[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.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/veth.c14
1 files changed, 1 insertions, 13 deletions
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 43af9e9b2652..3f67a29593bc 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -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);