From 14e98d86ac7a0e7725fb3a38fa8d2c643d03db50 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 5 Jul 2016 12:03:44 +0200 Subject: [PATCH 1/2] batman-adv: Add reference counting + nullptr fixes * Avoid nullptr dereference in bla after vlan_insert_tag * Avoid nullptr dereference in dat after vlan_insert_tag * Avoid tt_req_node list put for unhashed entry * Fix orig_node_vlan leak on orig_node_release * Fix non-atomic bla_claim::backbone_gw access * Fix reference leak in batadv_find_router * Free last_bonding_candidate on release of orig_node Signed-off-by: Sven Eckelmann --- ...-nullptr-dereference-in-bla-after-vl.patch | 35 +++ ...-nullptr-dereference-in-dat-after-vl.patch | 49 +++ ...-tt_req_node-list-put-for-unhashed-e.patch | 41 +++ ...rig_node_vlan-leak-on-orig_node_rele.patch | 43 +++ ...on-atomic-bla_claim-backbone_gw-acce.patch | 291 ++++++++++++++++++ ...reference-leak-in-batadv_find_router.patch | 120 ++++++++ ...last_bonding_candidate-on-release-of.patch | 45 +++ 7 files changed, 624 insertions(+) create mode 100644 batman-adv/patches/0015-batman-adv-Avoid-nullptr-dereference-in-bla-after-vl.patch create mode 100644 batman-adv/patches/0016-batman-adv-Avoid-nullptr-dereference-in-dat-after-vl.patch create mode 100644 batman-adv/patches/0017-batman-adv-Avoid-tt_req_node-list-put-for-unhashed-e.patch create mode 100644 batman-adv/patches/0018-batman-adv-Fix-orig_node_vlan-leak-on-orig_node_rele.patch create mode 100644 batman-adv/patches/0019-batman-adv-Fix-non-atomic-bla_claim-backbone_gw-acce.patch create mode 100644 batman-adv/patches/0020-batman-adv-Fix-reference-leak-in-batadv_find_router.patch create mode 100644 batman-adv/patches/0021-batman-adv-Free-last_bonding_candidate-on-release-of.patch diff --git a/batman-adv/patches/0015-batman-adv-Avoid-nullptr-dereference-in-bla-after-vl.patch b/batman-adv/patches/0015-batman-adv-Avoid-nullptr-dereference-in-bla-after-vl.patch new file mode 100644 index 0000000..907c1a1 --- /dev/null +++ b/batman-adv/patches/0015-batman-adv-Avoid-nullptr-dereference-in-bla-after-vl.patch @@ -0,0 +1,35 @@ +From: Sven Eckelmann +Date: Sat, 2 Jul 2016 09:52:13 +0200 +Subject: [PATCH] batman-adv: Avoid nullptr dereference in bla after vlan_insert_tag + +vlan_insert_tag can return NULL on errors. The bridge loop avoidance code +therefore has to check the return value of vlan_insert_tag for NULL before +it can safely operate on this pointer. + +Fixes: a9ce0dc43e2c ("batman-adv: add basic bridge loop avoidance code") +Signed-off-by: Sven Eckelmann +Signed-off-by: Marek Lindner + +Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/e4cffba4d3353ea15287abbfbdd65208aa62c156 +--- + net/batman-adv/bridge_loop_avoidance.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c +index 0a6c8b8..fe8b62f 100644 +--- a/net/batman-adv/bridge_loop_avoidance.c ++++ b/net/batman-adv/bridge_loop_avoidance.c +@@ -409,9 +409,12 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac, + break; + } + +- if (vid & BATADV_VLAN_HAS_TAG) ++ if (vid & BATADV_VLAN_HAS_TAG) { + skb = vlan_insert_tag(skb, htons(ETH_P_8021Q), + vid & VLAN_VID_MASK); ++ if (!skb) ++ goto out; ++ } + + skb_reset_mac_header(skb); + skb->protocol = eth_type_trans(skb, soft_iface); diff --git a/batman-adv/patches/0016-batman-adv-Avoid-nullptr-dereference-in-dat-after-vl.patch b/batman-adv/patches/0016-batman-adv-Avoid-nullptr-dereference-in-dat-after-vl.patch new file mode 100644 index 0000000..d896811 --- /dev/null +++ b/batman-adv/patches/0016-batman-adv-Avoid-nullptr-dereference-in-dat-after-vl.patch @@ -0,0 +1,49 @@ +From: Sven Eckelmann +Date: Sat, 2 Jul 2016 09:52:14 +0200 +Subject: [PATCH] batman-adv: Avoid nullptr dereference in dat after vlan_insert_tag + +vlan_insert_tag can return NULL on errors. The distributed arp table code +therefore has to check the return value of vlan_insert_tag for NULL before +it can safely operate on this pointer. + +Fixes: 53c6c262a581 ("batman-adv: tag locally generated ARP reply if needed") +Signed-off-by: Sven Eckelmann +Signed-off-by: Marek Lindner + +Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/898382d11fa1f737cd4f7033db1088c601fd11ed +--- + net/batman-adv/distributed-arp-table.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c +index 3e6b262..5a89be0 100644 +--- a/net/batman-adv/distributed-arp-table.c ++++ b/net/batman-adv/distributed-arp-table.c +@@ -1009,9 +1009,12 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, + if (!skb_new) + goto out; + +- if (vid & BATADV_VLAN_HAS_TAG) ++ if (vid & BATADV_VLAN_HAS_TAG) { + skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q), + vid & VLAN_VID_MASK); ++ if (!skb_new) ++ goto out; ++ } + + skb_reset_mac_header(skb_new); + skb_new->protocol = eth_type_trans(skb_new, +@@ -1089,9 +1092,12 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, + */ + skb_reset_mac_header(skb_new); + +- if (vid & BATADV_VLAN_HAS_TAG) ++ if (vid & BATADV_VLAN_HAS_TAG) { + skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q), + vid & VLAN_VID_MASK); ++ if (!skb_new) ++ goto out; ++ } + + /* To preserve backwards compatibility, the node has choose the outgoing + * format based on the incoming request packet type. The assumption is diff --git a/batman-adv/patches/0017-batman-adv-Avoid-tt_req_node-list-put-for-unhashed-e.patch b/batman-adv/patches/0017-batman-adv-Avoid-tt_req_node-list-put-for-unhashed-e.patch new file mode 100644 index 0000000..09f90d3 --- /dev/null +++ b/batman-adv/patches/0017-batman-adv-Avoid-tt_req_node-list-put-for-unhashed-e.patch @@ -0,0 +1,41 @@ +From: Sven Eckelmann +Date: Fri, 24 Jun 2016 21:43:32 +0200 +Subject: [PATCH] batman-adv: Avoid tt_req_node list put for unhashed entry + +It can happen that a tt_req_node list entry was already removed from +tt.req_list when batadv_send_tt_request reaches the end of the function. +The reference counter was already reduced by 1 for the list entry and thus +the reference counter is not allowed to be reduced again. Otherwise, the +entry is freed too early and the next batadv_tt_req_node_put in this +function will operate on freed memory. + +Fixes: cea194d90b11 ("batman-adv: improved client announcement mechanism") +Signed-off-by: Sven Eckelmann +Signed-off-by: Marek Lindner + +Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/03ecc9f957b837c755f09251c5f684996521e487 +--- + net/batman-adv/translation-table.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c +index 23fb7ea..f7d44c6 100644 +--- a/net/batman-adv/translation-table.c ++++ b/net/batman-adv/translation-table.c +@@ -2639,11 +2639,13 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv, + out: + if (primary_if) + batadv_hardif_put(primary_if); ++ + if (ret && tt_req_node) { + spin_lock_bh(&bat_priv->tt.req_list_lock); +- /* hlist_del_init() verifies tt_req_node still is in the list */ +- hlist_del_init(&tt_req_node->list); +- batadv_tt_req_node_put(tt_req_node); ++ if (!hlist_unhashed(&tt_req_node->list)) { ++ hlist_del_init(&tt_req_node->list); ++ batadv_tt_req_node_put(tt_req_node); ++ } + spin_unlock_bh(&bat_priv->tt.req_list_lock); + } + diff --git a/batman-adv/patches/0018-batman-adv-Fix-orig_node_vlan-leak-on-orig_node_rele.patch b/batman-adv/patches/0018-batman-adv-Fix-orig_node_vlan-leak-on-orig_node_rele.patch new file mode 100644 index 0000000..13c74e4 --- /dev/null +++ b/batman-adv/patches/0018-batman-adv-Fix-orig_node_vlan-leak-on-orig_node_rele.patch @@ -0,0 +1,43 @@ +From: Sven Eckelmann +Date: Thu, 30 Jun 2016 20:10:46 +0200 +Subject: [PATCH] batman-adv: Fix orig_node_vlan leak on orig_node_release + +batadv_orig_node_new uses batadv_orig_node_vlan_new to allocate a new +batadv_orig_node_vlan and add it to batadv_orig_node::vlan_list. References +to this list have also to be cleaned when the batadv_orig_node is removed. + +Fixes: 21a57f6e7a3b ("batman-adv: make the TT CRC logic VLAN specific") +Signed-off-by: Sven Eckelmann +Signed-off-by: Marek Lindner + +Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/719afd254e812c7ff8688ce79bebb7324ec438d6 +--- + net/batman-adv/originator.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c +index 28241a4..3a3948a 100644 +--- a/net/batman-adv/originator.c ++++ b/net/batman-adv/originator.c +@@ -781,6 +781,7 @@ static void batadv_orig_node_release(struct kref *ref) + struct batadv_neigh_node *neigh_node; + struct batadv_orig_node *orig_node; + struct batadv_orig_ifinfo *orig_ifinfo; ++ struct batadv_orig_node_vlan *vlan; + + orig_node = container_of(ref, struct batadv_orig_node, refcount); + +@@ -800,6 +801,13 @@ static void batadv_orig_node_release(struct kref *ref) + } + spin_unlock_bh(&orig_node->neigh_list_lock); + ++ spin_lock_bh(&orig_node->vlan_list_lock); ++ hlist_for_each_entry_safe(vlan, node_tmp, &orig_node->vlan_list, list) { ++ hlist_del_rcu(&vlan->list); ++ batadv_orig_node_vlan_put(vlan); ++ } ++ spin_unlock_bh(&orig_node->vlan_list_lock); ++ + /* Free nc_nodes */ + batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL); + diff --git a/batman-adv/patches/0019-batman-adv-Fix-non-atomic-bla_claim-backbone_gw-acce.patch b/batman-adv/patches/0019-batman-adv-Fix-non-atomic-bla_claim-backbone_gw-acce.patch new file mode 100644 index 0000000..9631ebe --- /dev/null +++ b/batman-adv/patches/0019-batman-adv-Fix-non-atomic-bla_claim-backbone_gw-acce.patch @@ -0,0 +1,291 @@ +From: Sven Eckelmann +Date: Fri, 1 Jul 2016 15:49:43 +0200 +Subject: [PATCH] batman-adv: Fix non-atomic bla_claim::backbone_gw access + +The pointer batadv_bla_claim::backbone_gw can be changed at any time. +Therefore, access to it must be protected to ensure that two function +accessing the same backbone_gw are actually accessing the same. This is +especially important when the crc_lock is used or when the backbone_gw of a +claim is exchanged. + +Not doing so leads to invalid memory access and/or reference leaks. + +Fixes: a9ce0dc43e2c ("batman-adv: add basic bridge loop avoidance code") +Fixes: b307e72d119f ("batman-adv: lock crc access in bridge loop avoidance") +Signed-off-by: Sven Eckelmann +Acked-by: Simon Wunderlich +Signed-off-by: Marek Lindner + +Origin: backport, https://git.open-mesh.org/batman-adv.git/commit/e401297e3a393896e9b07bef8d6e2df203b60d43 +--- + net/batman-adv/bridge_loop_avoidance.c | 111 ++++++++++++++++++++++++++------- + net/batman-adv/types.h | 2 + + 2 files changed, 90 insertions(+), 23 deletions(-) + +diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c +index fe8b62f..30fd72e 100644 +--- a/net/batman-adv/bridge_loop_avoidance.c ++++ b/net/batman-adv/bridge_loop_avoidance.c +@@ -176,10 +176,21 @@ static void batadv_backbone_gw_put(struct batadv_bla_backbone_gw *backbone_gw) + static void batadv_claim_release(struct kref *ref) + { + struct batadv_bla_claim *claim; ++ struct batadv_bla_backbone_gw *old_backbone_gw; + + claim = container_of(ref, struct batadv_bla_claim, refcount); + +- batadv_backbone_gw_put(claim->backbone_gw); ++ spin_lock_bh(&claim->backbone_lock); ++ old_backbone_gw = claim->backbone_gw; ++ claim->backbone_gw = NULL; ++ spin_unlock_bh(&claim->backbone_lock); ++ ++ spin_lock_bh(&old_backbone_gw->crc_lock); ++ old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); ++ spin_unlock_bh(&old_backbone_gw->crc_lock); ++ ++ batadv_backbone_gw_put(old_backbone_gw); ++ + kfree_rcu(claim, rcu); + } + +@@ -637,8 +648,10 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, + const u8 *mac, const unsigned short vid, + struct batadv_bla_backbone_gw *backbone_gw) + { ++ struct batadv_bla_backbone_gw *old_backbone_gw; + struct batadv_bla_claim *claim; + struct batadv_bla_claim search_claim; ++ bool remove_crc = false; + int hash_added; + + ether_addr_copy(search_claim.addr, mac); +@@ -652,8 +665,10 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, + return; + + ether_addr_copy(claim->addr, mac); ++ spin_lock_init(&claim->backbone_lock); + claim->vid = vid; + claim->lasttime = jiffies; ++ kref_get(&backbone_gw->refcount); + claim->backbone_gw = backbone_gw; + + kref_init(&claim->refcount); +@@ -681,15 +696,26 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, + "bla_add_claim(): changing ownership for %pM, vid %d\n", + mac, BATADV_PRINT_VID(vid)); + +- spin_lock_bh(&claim->backbone_gw->crc_lock); +- claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); +- spin_unlock_bh(&claim->backbone_gw->crc_lock); +- batadv_backbone_gw_put(claim->backbone_gw); ++ remove_crc = true; + } +- /* set (new) backbone gw */ ++ ++ /* replace backbone_gw atomically and adjust reference counters */ ++ spin_lock_bh(&claim->backbone_lock); ++ old_backbone_gw = claim->backbone_gw; + kref_get(&backbone_gw->refcount); + claim->backbone_gw = backbone_gw; ++ spin_unlock_bh(&claim->backbone_lock); + ++ if (remove_crc) { ++ /* remove claim address from old backbone_gw */ ++ spin_lock_bh(&old_backbone_gw->crc_lock); ++ old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); ++ spin_unlock_bh(&old_backbone_gw->crc_lock); ++ } ++ ++ batadv_backbone_gw_put(old_backbone_gw); ++ ++ /* add claim address to new backbone_gw */ + spin_lock_bh(&backbone_gw->crc_lock); + backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); + spin_unlock_bh(&backbone_gw->crc_lock); +@@ -700,6 +726,26 @@ claim_free_ref: + } + + /** ++ * batadv_bla_claim_get_backbone_gw - Get valid reference for backbone_gw of ++ * claim ++ * @claim: claim whose backbone_gw should be returned ++ * ++ * Return: valid reference to claim::backbone_gw ++ */ ++static struct batadv_bla_backbone_gw * ++batadv_bla_claim_get_backbone_gw(struct batadv_bla_claim *claim) ++{ ++ struct batadv_bla_backbone_gw *backbone_gw; ++ ++ spin_lock_bh(&claim->backbone_lock); ++ backbone_gw = claim->backbone_gw; ++ kref_get(&backbone_gw->refcount); ++ spin_unlock_bh(&claim->backbone_lock); ++ ++ return backbone_gw; ++} ++ ++/** + * batadv_bla_del_claim - delete a claim from the claim hash + * @bat_priv: the bat priv with all the soft interface information + * @mac: mac address of the claim to be removed +@@ -723,10 +769,6 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv, + batadv_choose_claim, claim); + batadv_claim_put(claim); /* reference from the hash is gone */ + +- spin_lock_bh(&claim->backbone_gw->crc_lock); +- claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); +- spin_unlock_bh(&claim->backbone_gw->crc_lock); +- + /* don't need the reference from hash_find() anymore */ + batadv_claim_put(claim); + } +@@ -1175,6 +1217,7 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv, + struct batadv_hard_iface *primary_if, + int now) + { ++ struct batadv_bla_backbone_gw *backbone_gw; + struct batadv_bla_claim *claim; + struct hlist_head *head; + struct batadv_hashtable *hash; +@@ -1189,14 +1232,17 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv, + + rcu_read_lock(); + hlist_for_each_entry_rcu(claim, head, hash_entry) { ++ backbone_gw = batadv_bla_claim_get_backbone_gw(claim); + if (now) + goto purge_now; +- if (!batadv_compare_eth(claim->backbone_gw->orig, ++ ++ if (!batadv_compare_eth(backbone_gw->orig, + primary_if->net_dev->dev_addr)) +- continue; ++ goto skip; ++ + if (!batadv_has_timed_out(claim->lasttime, + BATADV_BLA_CLAIM_TIMEOUT)) +- continue; ++ goto skip; + + batadv_dbg(BATADV_DBG_BLA, bat_priv, + "bla_purge_claims(): %pM, vid %d, time out\n", +@@ -1204,8 +1250,10 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv, + + purge_now: + batadv_handle_unclaim(bat_priv, primary_if, +- claim->backbone_gw->orig, ++ backbone_gw->orig, + claim->addr, claim->vid); ++skip: ++ batadv_backbone_gw_put(backbone_gw); + } + rcu_read_unlock(); + } +@@ -1623,9 +1671,11 @@ void batadv_bla_free(struct batadv_priv *bat_priv) + int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, + unsigned short vid, bool is_bcast) + { ++ struct batadv_bla_backbone_gw *backbone_gw; + struct ethhdr *ethhdr; + struct batadv_bla_claim search_claim, *claim = NULL; + struct batadv_hard_iface *primary_if; ++ bool own_claim; + int ret; + + ethhdr = eth_hdr(skb); +@@ -1657,8 +1707,12 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, + } + + /* if it is our own claim ... */ +- if (batadv_compare_eth(claim->backbone_gw->orig, +- primary_if->net_dev->dev_addr)) { ++ backbone_gw = batadv_bla_claim_get_backbone_gw(claim); ++ own_claim = batadv_compare_eth(backbone_gw->orig, ++ primary_if->net_dev->dev_addr); ++ batadv_backbone_gw_put(backbone_gw); ++ ++ if (own_claim) { + /* ... allow it in any case */ + claim->lasttime = jiffies; + goto allow; +@@ -1722,7 +1776,9 @@ int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, + { + struct ethhdr *ethhdr; + struct batadv_bla_claim search_claim, *claim = NULL; ++ struct batadv_bla_backbone_gw *backbone_gw; + struct batadv_hard_iface *primary_if; ++ bool client_roamed; + int ret = 0; + + primary_if = batadv_primary_if_get_selected(bat_priv); +@@ -1752,8 +1808,12 @@ int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, + goto allow; + + /* check if we are responsible. */ +- if (batadv_compare_eth(claim->backbone_gw->orig, +- primary_if->net_dev->dev_addr)) { ++ backbone_gw = batadv_bla_claim_get_backbone_gw(claim); ++ client_roamed = batadv_compare_eth(backbone_gw->orig, ++ primary_if->net_dev->dev_addr); ++ batadv_backbone_gw_put(backbone_gw); ++ ++ if (client_roamed) { + /* if yes, the client has roamed and we have + * to unclaim it. + */ +@@ -1801,6 +1861,7 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset) + struct net_device *net_dev = (struct net_device *)seq->private; + struct batadv_priv *bat_priv = netdev_priv(net_dev); + struct batadv_hashtable *hash = bat_priv->bla.claim_hash; ++ struct batadv_bla_backbone_gw *backbone_gw; + struct batadv_bla_claim *claim; + struct batadv_hard_iface *primary_if; + struct hlist_head *head; +@@ -1825,17 +1886,21 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset) + + rcu_read_lock(); + hlist_for_each_entry_rcu(claim, head, hash_entry) { +- is_own = batadv_compare_eth(claim->backbone_gw->orig, ++ backbone_gw = batadv_bla_claim_get_backbone_gw(claim); ++ ++ is_own = batadv_compare_eth(backbone_gw->orig, + primary_addr); + +- spin_lock_bh(&claim->backbone_gw->crc_lock); +- backbone_crc = claim->backbone_gw->crc; +- spin_unlock_bh(&claim->backbone_gw->crc_lock); ++ spin_lock_bh(&backbone_gw->crc_lock); ++ backbone_crc = backbone_gw->crc; ++ spin_unlock_bh(&backbone_gw->crc_lock); + seq_printf(seq, " * %pM on %5d by %pM [%c] (%#.4x)\n", + claim->addr, BATADV_PRINT_VID(claim->vid), +- claim->backbone_gw->orig, ++ backbone_gw->orig, + (is_own ? 'x' : ' '), + backbone_crc); ++ ++ batadv_backbone_gw_put(backbone_gw); + } + rcu_read_unlock(); + } +diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h +index d75beef..41a85b5 100644 +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -1034,6 +1034,7 @@ struct batadv_bla_backbone_gw { + * @addr: mac address of claimed non-mesh client + * @vid: vlan id this client was detected on + * @backbone_gw: pointer to backbone gw claiming this client ++ * @backbone_lock: lock protecting backbone_gw pointer + * @lasttime: last time we heard of claim (locals only) + * @hash_entry: hlist node for batadv_priv_bla::claim_hash + * @refcount: number of contexts the object is used +@@ -1043,6 +1044,7 @@ struct batadv_bla_claim { + u8 addr[ETH_ALEN]; + unsigned short vid; + struct batadv_bla_backbone_gw *backbone_gw; ++ spinlock_t backbone_lock; /* protects backbone_gw */ + unsigned long lasttime; + struct hlist_node hash_entry; + struct rcu_head rcu; diff --git a/batman-adv/patches/0020-batman-adv-Fix-reference-leak-in-batadv_find_router.patch b/batman-adv/patches/0020-batman-adv-Fix-reference-leak-in-batadv_find_router.patch new file mode 100644 index 0000000..38956cf --- /dev/null +++ b/batman-adv/patches/0020-batman-adv-Fix-reference-leak-in-batadv_find_router.patch @@ -0,0 +1,120 @@ +From: Sven Eckelmann +Date: Thu, 30 Jun 2016 20:11:34 +0200 +Subject: [PATCH] batman-adv: Fix reference leak in batadv_find_router + +The replacement of last_bonding_candidate in batadv_orig_node has to be an +atomic operation. Otherwise it is possible that the reference counter of a +batadv_orig_ifinfo is reduced which was no longer the +last_bonding_candidate when the new candidate is added. This can either +lead to an invalid memory access or to reference leaks which make it +impossible to an interface which was added to batman-adv. + +Fixes: 797edd9e87ac ("batman-adv: add bonding again") +Signed-off-by: Sven Eckelmann +Acked-by: Simon Wunderlich +Signed-off-by: Marek Lindner + +Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/6ecc711374afd93ee0c2216b38ae52d3ce680c3f +--- + net/batman-adv/routing.c | 52 ++++++++++++++++++++++++++++++++++++------------ + net/batman-adv/types.h | 4 +++- + 2 files changed, 42 insertions(+), 14 deletions(-) + +diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c +index 27e07dd..694dc74 100644 +--- a/net/batman-adv/routing.c ++++ b/net/batman-adv/routing.c +@@ -456,6 +456,29 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv, + } + + /** ++ * batadv_last_bonding_replace - Replace last_bonding_candidate of orig_node ++ * @orig_node: originator node whose bonding candidates should be replaced ++ * @new_candidate: new bonding candidate or NULL ++ */ ++static void ++batadv_last_bonding_replace(struct batadv_orig_node *orig_node, ++ struct batadv_orig_ifinfo *new_candidate) ++{ ++ struct batadv_orig_ifinfo *old_candidate; ++ ++ spin_lock_bh(&orig_node->neigh_list_lock); ++ old_candidate = orig_node->last_bonding_candidate; ++ ++ if (new_candidate) ++ kref_get(&new_candidate->refcount); ++ orig_node->last_bonding_candidate = new_candidate; ++ spin_unlock_bh(&orig_node->neigh_list_lock); ++ ++ if (old_candidate) ++ batadv_orig_ifinfo_put(old_candidate); ++} ++ ++/** + * batadv_find_router - find a suitable router for this originator + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: the destination node +@@ -562,10 +585,6 @@ next: + } + rcu_read_unlock(); + +- /* last_bonding_candidate is reset below, remove the old reference. */ +- if (orig_node->last_bonding_candidate) +- batadv_orig_ifinfo_put(orig_node->last_bonding_candidate); +- + /* After finding candidates, handle the three cases: + * 1) there is a next candidate, use that + * 2) there is no next candidate, use the first of the list +@@ -574,21 +593,28 @@ next: + if (next_candidate) { + batadv_neigh_node_put(router); + +- /* remove references to first candidate, we don't need it. */ +- if (first_candidate) { +- batadv_neigh_node_put(first_candidate_router); +- batadv_orig_ifinfo_put(first_candidate); +- } ++ kref_get(&next_candidate_router->refcount); + router = next_candidate_router; +- orig_node->last_bonding_candidate = next_candidate; ++ batadv_last_bonding_replace(orig_node, next_candidate); + } else if (first_candidate) { + batadv_neigh_node_put(router); + +- /* refcounting has already been done in the loop above. */ ++ kref_get(&first_candidate_router->refcount); + router = first_candidate_router; +- orig_node->last_bonding_candidate = first_candidate; ++ batadv_last_bonding_replace(orig_node, first_candidate); + } else { +- orig_node->last_bonding_candidate = NULL; ++ batadv_last_bonding_replace(orig_node, NULL); ++ } ++ ++ /* cleanup of candidates */ ++ if (first_candidate) { ++ batadv_neigh_node_put(first_candidate_router); ++ batadv_orig_ifinfo_put(first_candidate); ++ } ++ ++ if (next_candidate) { ++ batadv_neigh_node_put(next_candidate_router); ++ batadv_orig_ifinfo_put(next_candidate); + } + + return router; +diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h +index 41a85b5..c143649 100644 +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -330,7 +330,9 @@ struct batadv_orig_node { + DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); + u32 last_bcast_seqno; + struct hlist_head neigh_list; +- /* neigh_list_lock protects: neigh_list and router */ ++ /* neigh_list_lock protects: neigh_list, ifinfo_list, ++ * last_bonding_candidate and router ++ */ + spinlock_t neigh_list_lock; + struct hlist_node hash_entry; + struct batadv_priv *bat_priv; diff --git a/batman-adv/patches/0021-batman-adv-Free-last_bonding_candidate-on-release-of.patch b/batman-adv/patches/0021-batman-adv-Free-last_bonding_candidate-on-release-of.patch new file mode 100644 index 0000000..b35a801 --- /dev/null +++ b/batman-adv/patches/0021-batman-adv-Free-last_bonding_candidate-on-release-of.patch @@ -0,0 +1,45 @@ +From: Sven Eckelmann +Date: Thu, 30 Jun 2016 21:41:13 +0200 +Subject: [PATCH] batman-adv: Free last_bonding_candidate on release of orig_node + +The orig_ifinfo reference counter for last_bonding_candidate in +batadv_orig_node has to be reduced when an originator node is released. +Otherwise the orig_ifinfo is leaked and the reference counter the netdevice +is not reduced correctly. + +Fixes: 797edd9e87ac ("batman-adv: add bonding again") +Signed-off-by: Sven Eckelmann +Signed-off-by: Marek Lindner + +Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/20df5c53865a90095099f0af80536b8abfea303b +--- + net/batman-adv/originator.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c +index 3a3948a..7594afd 100644 +--- a/net/batman-adv/originator.c ++++ b/net/batman-adv/originator.c +@@ -782,6 +782,7 @@ static void batadv_orig_node_release(struct kref *ref) + struct batadv_orig_node *orig_node; + struct batadv_orig_ifinfo *orig_ifinfo; + struct batadv_orig_node_vlan *vlan; ++ struct batadv_orig_ifinfo *last_candidate; + + orig_node = container_of(ref, struct batadv_orig_node, refcount); + +@@ -799,8 +800,14 @@ static void batadv_orig_node_release(struct kref *ref) + hlist_del_rcu(&orig_ifinfo->list); + batadv_orig_ifinfo_put(orig_ifinfo); + } ++ ++ last_candidate = orig_node->last_bonding_candidate; ++ orig_node->last_bonding_candidate = NULL; + spin_unlock_bh(&orig_node->neigh_list_lock); + ++ if (last_candidate) ++ batadv_orig_ifinfo_put(last_candidate); ++ + spin_lock_bh(&orig_node->vlan_list_lock); + hlist_for_each_entry_safe(vlan, node_tmp, &orig_node->vlan_list, list) { + hlist_del_rcu(&vlan->list); From 0d86d08be9a696f33ef2eaed0516e459a34a083e Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 17 Jun 2016 15:54:03 +0200 Subject: [PATCH 2/2] batman-adv: Fix speedy join in gateway client mode Speedy join only works when the received packet is either broadcast or an 4addr unicast packet. Thus packets converted from broadcast to unicast via the gateway handling code have to be converted to 4addr packets to allow the receiving gateway server to add the sender address as temporary entry to the translation table. Not doing it will make the batman-adv gateway server drop the DHCP response in many situations because it doesn't yet have the TT entry for the destination of the DHCP response. Signed-off-by: Sven Eckelmann --- batman-adv/Makefile | 2 +- ...x-speedy-join-in-gateway-client-mode.patch | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 batman-adv/patches/0022-batman-adv-Fix-speedy-join-in-gateway-client-mode.patch diff --git a/batman-adv/Makefile b/batman-adv/Makefile index d222c0b..e8334d5 100644 --- a/batman-adv/Makefile +++ b/batman-adv/Makefile @@ -11,7 +11,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=batman-adv PKG_VERSION:=2016.1 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_MD5SUM:=8c8e449009b4d29512d26ee308960bb5 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz diff --git a/batman-adv/patches/0022-batman-adv-Fix-speedy-join-in-gateway-client-mode.patch b/batman-adv/patches/0022-batman-adv-Fix-speedy-join-in-gateway-client-mode.patch new file mode 100644 index 0000000..fa61a1b --- /dev/null +++ b/batman-adv/patches/0022-batman-adv-Fix-speedy-join-in-gateway-client-mode.patch @@ -0,0 +1,35 @@ +From: Sven Eckelmann +Date: Sun, 12 Jun 2016 10:43:19 +0200 +Subject: [PATCH] batman-adv: Fix speedy join in gateway client mode + +Speedy join only works when the received packet is either broadcast or an +4addr unicast packet. Thus packets converted from broadcast to unicast via +the gateway handling code have to be converted to 4addr packets to allow +the receiving gateway server to add the sender address as temporary entry +to the translation table. + +Not doing it will make the batman-adv gateway server drop the DHCP response +in many situations because it doesn't yet have the TT entry for the +destination of the DHCP response. + +Fixes: 9cbc67d9da47 ("batman-adv: change interface_rx to get orig node") +Signed-off-by: Sven Eckelmann +--- + net/batman-adv/send.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c +index 7641785..e5be212 100644 +--- a/net/batman-adv/send.c ++++ b/net/batman-adv/send.c +@@ -423,8 +423,8 @@ int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, + struct batadv_orig_node *orig_node; + + orig_node = batadv_gw_get_selected_orig(bat_priv); +- return batadv_send_skb_unicast(bat_priv, skb, BATADV_UNICAST, 0, +- orig_node, vid); ++ return batadv_send_skb_unicast(bat_priv, skb, BATADV_UNICAST_4ADDR, ++ BATADV_P_DATA, orig_node, vid); + } + + void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface)