Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=68365458a4252fa993b91a00f7a0b18fed399f0d
Commit:     68365458a4252fa993b91a00f7a0b18fed399f0d
Parent:     d4782c323d10d3698b71b6a6b3c7bdad33824658
Author:     Patrick McHardy <[EMAIL PROTECTED]>
AuthorDate: Sun Jan 20 17:25:14 2008 -0800
Committer:  David S. Miller <[EMAIL PROTECTED]>
CommitDate: Sun Jan 20 20:31:45 2008 -0800

    [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 <[EMAIL PROTECTED]>
    Signed-off-by: David S. Miller <[EMAIL PROTECTED]>
---
 drivers/net/veth.c   |   14 +-------------
 net/core/rtnetlink.c |    5 ++++-
 2 files changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 43af9e9..3f67a29 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);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index e1ba26f..fed95a3 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -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);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to