Hi,

Currently, there is an otherwise hard-to-fix race in
br_handle_frame.

When a packet is received on a device that's enslaved to a
bridge device, it is handed from net_rx_action (or
netif_receive_skb in the NAPI case) to the bridge code, and the
bridge code has to do a net_device->net_bridge mapping to find
the parent.  But, somebody could be unlinking this device from
its parent at the same time as we're trying to lookup the parent.

This is pretty much impossible to fix without using some kind
of 'global' synchronisation, and I could find no better lock to
reuse than BR_NETPROTO_LOCK.  It makes sense to reuse this lock
as it protects all global state that the netif_rx_action path
relies on, and the bridge port lists are such state.

Please consider.


cheers,
Lennert


--- linux-2.4.19-rxatomic-minimal/net/bridge/br_if.c.orig       2002-10-02 
10:17:38.000000000 +0200
+++ linux-2.4.19-rxatomic-minimal/net/bridge/br_if.c    2002-10-02 10:19:38.000000000 
++0200
@@ -18,6 +18,7 @@
 #include <linux/if_bridge.h>
 #include <linux/inetdevice.h>
 #include <linux/rtnetlink.h>
+#include <linux/brlock.h>
 #include <asm/uaccess.h>
 #include "br_private.h"
 
@@ -37,7 +37,7 @@
        return 100;
 }
 
-/* called under bridge lock */
+/* called under BR_NETPROTO_LOCK and bridge lock */
 static int __br_del_if(struct net_bridge *br, struct net_device *dev)
 {
        struct net_bridge_port *p;
@@ -86,10 +86,12 @@
 
 static void del_ifs(struct net_bridge *br)
 {
-       write_lock_bh(&br->lock);
+       br_write_lock_bh(BR_NETPROTO_LOCK);
+       write_lock(&br->lock);
        while (br->port_list != NULL)
                __br_del_if(br, br->port_list->dev);
-       write_unlock_bh(&br->lock);
+       write_unlock(&br->lock);
+       br_write_unlock_bh(BR_NETPROTO_LOCK);
 }
 
 static struct net_bridge *new_nb(char *name)
@@ -252,10 +254,12 @@
 {
        int retval;
 
-       write_lock_bh(&br->lock);
+       br_write_lock_bh(BR_NETPROTO_LOCK);
+       write_lock(&br->lock);
        retval = __br_del_if(br, dev);
        br_stp_recalculate_bridge_id(br);
-       write_unlock_bh(&br->lock);
+       write_unlock(&br->lock);
+       br_write_unlock_bh(BR_NETPROTO_LOCK);
 
        return retval;
 }
_______________________________________________
Bridge mailing list
[EMAIL PROTECTED]
http://www.math.leidenuniv.nl/mailman/listinfo/bridge

Reply via email to