Repository : ssh://git@open-mesh.org/batman-adv
On branch : next
commit 4c1721b39c8a77c99e8f4de97b5d5d112006406c Author: Linus Lüssing linus.luessing@web.de Date: Wed Oct 17 14:53:05 2012 +0200
batman-adv: Fix potential broadcast BLA-duplicate-check race condition
Threads in the bottom half of batadv_bla_check_bcast_duplist() might otherwise for instance overwrite variables which other threads might be using/reading at the same time in the top half, potentially leading to messing up the bcast_duplist, possibly resulting in false bridge loop avoidance duplicate check decisions.
Signed-off-by: Linus Lüssing linus.luessing@web.de Acked-by: Simon Wunderlich siwu@hrz.tu-chemnitz.de Signed-off-by: Marek Lindner lindner_marek@yahoo.de
4c1721b39c8a77c99e8f4de97b5d5d112006406c bridge_loop_avoidance.c | 16 +++++++++++----- main.c | 1 + types.h | 2 ++ 3 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/bridge_loop_avoidance.c b/bridge_loop_avoidance.c index eebab20..9a4b24f 100644 --- a/bridge_loop_avoidance.c +++ b/bridge_loop_avoidance.c @@ -1226,7 +1226,7 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, struct batadv_bcast_packet *bcast_packet, int bcast_packet_len) { - int i, length, curr; + int i, length, curr, ret = 0; uint8_t *content; uint16_t crc; struct batadv_bcast_duplist_entry *entry; @@ -1238,6 +1238,8 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, /* calculate the crc ... */ crc = crc16(0, content, length);
+ spin_lock_bh(&bat_priv->bla.bcast_duplist_lock); + for (i = 0; i < BATADV_DUPLIST_SIZE; i++) { curr = (bat_priv->bla.bcast_duplist_curr + i); curr %= BATADV_DUPLIST_SIZE; @@ -1259,9 +1261,11 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, /* this entry seems to match: same crc, not too old, * and from another gw. therefore return 1 to forbid it. */ - return 1; + ret = 1; + goto out; } - /* not found, add a new entry (overwrite the oldest entry) */ + /* not found, add a new entry (overwrite the oldest entry) + * and allow it, its the first occurence. */ curr = (bat_priv->bla.bcast_duplist_curr + BATADV_DUPLIST_SIZE - 1); curr %= BATADV_DUPLIST_SIZE; entry = &bat_priv->bla.bcast_duplist[curr]; @@ -1270,8 +1274,10 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, memcpy(entry->orig, bcast_packet->orig, ETH_ALEN); bat_priv->bla.bcast_duplist_curr = curr;
- /* allow it, its the first occurence. */ - return 0; +out: + spin_unlock_bh(&bat_priv->bla.bcast_duplist_lock); + + return ret; }
diff --git a/main.c b/main.c index b4aa470..f167b65 100644 --- a/main.c +++ b/main.c @@ -101,6 +101,7 @@ int batadv_mesh_init(struct net_device *soft_iface) spin_lock_init(&bat_priv->gw.list_lock); spin_lock_init(&bat_priv->vis.hash_lock); spin_lock_init(&bat_priv->vis.list_lock); + spin_lock_init(&bat_priv->bla.bcast_duplist_lock);
INIT_HLIST_HEAD(&bat_priv->forw_bat_list); INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); diff --git a/types.h b/types.h index 2ed82ca..ac1e07a 100644 --- a/types.h +++ b/types.h @@ -205,6 +205,8 @@ struct batadv_priv_bla { struct batadv_hashtable *backbone_hash; struct batadv_bcast_duplist_entry bcast_duplist[BATADV_DUPLIST_SIZE]; int bcast_duplist_curr; + /* protects bcast_duplist and bcast_duplist_curr */ + spinlock_t bcast_duplist_lock; struct batadv_bla_claim_dst claim_dest; struct delayed_work work; };