From 63d443efe8be2c1d02b30d7e4edeb9aa085352b3 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 10 May 2016 23:17:59 +0200 Subject: batman-adv: fix skb deref after free batadv_send_skb_to_orig() calls dev_queue_xmit() so we can't use skb->len. Fixes: 953324776d6d ("batman-adv: network coding - buffer unicast packets before forward") Signed-off-by: Florian Westphal Reviewed-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index ae850f2..e3857ed 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -601,6 +601,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, struct batadv_unicast_packet *unicast_packet; struct ethhdr *ethhdr = eth_hdr(skb); int res, hdr_len, ret = NET_RX_DROP; + unsigned int len; unicast_packet = (struct batadv_unicast_packet *)skb->data; @@ -641,6 +642,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, if (hdr_len > 0) batadv_skb_set_priority(skb, hdr_len); + len = skb->len; res = batadv_send_skb_to_orig(skb, orig_node, recv_if); /* translate transmit result into receive result */ @@ -648,7 +650,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, /* skb was transmitted and consumed */ batadv_inc_counter(bat_priv, BATADV_CNT_FORWARD); batadv_add_counter(bat_priv, BATADV_CNT_FORWARD_BYTES, - skb->len + ETH_HLEN); + len + ETH_HLEN); ret = NET_RX_SUCCESS; } else if (res == NET_XMIT_POLICED) { -- cgit v0.10.2 From a45e932a3c58eac11a7458c6888910e23f615077 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 6 May 2016 11:43:38 +0200 Subject: batman-adv: Avoid nullptr derefence in batadv_v_neigh_is_sob batadv_neigh_ifinfo_get can return NULL when it cannot find (even when only temporarily) anymore the neigh_ifinfo in the list neigh->ifinfo_list. This has to be checked to avoid kernel Oopses when the ifinfo is dereferenced. This a situation which isn't expected but is already handled by functions like batadv_v_neigh_cmp. The same kind of warning is therefore used before the function returns without dereferencing the pointers. Fixes: 9786906022eb ("batman-adv: B.A.T.M.A.N. V - implement neighbor comparison API calls") Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index 3ff8bd1..50bfcf8 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -276,6 +277,9 @@ static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1, ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); + if (WARN_ON(!ifinfo1 || !ifinfo2)) + return false; + threshold = ifinfo1->bat_v.throughput / 4; threshold = ifinfo1->bat_v.throughput - threshold; -- cgit v0.10.2 From 71f9d27daa2cbcca7159c27f0c0c381cc2dd1053 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 6 May 2016 11:43:39 +0200 Subject: batman-adv: Fix refcnt leak in batadv_v_neigh_* The functions batadv_neigh_ifinfo_get increase the reference counter of the batadv_neigh_ifinfo. These have to be reduced again when the reference is not used anymore to correctly free the objects. Fixes: 9786906022eb ("batman-adv: B.A.T.M.A.N. V - implement neighbor comparison API calls") Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index 50bfcf8..4f626a6 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -256,14 +256,23 @@ static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1, struct batadv_hard_iface *if_outgoing2) { struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2; + int ret = 0; ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); + if (WARN_ON(!ifinfo1)) + goto err_ifinfo1; + ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); + if (WARN_ON(!ifinfo2)) + goto err_ifinfo2; - if (WARN_ON(!ifinfo1 || !ifinfo2)) - return 0; + ret = ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput; - return ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput; + batadv_neigh_ifinfo_put(ifinfo2); +err_ifinfo2: + batadv_neigh_ifinfo_put(ifinfo1); +err_ifinfo1: + return ret; } static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1, @@ -273,17 +282,26 @@ static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1, { struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2; u32 threshold; + bool ret = false; ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); - ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); + if (WARN_ON(!ifinfo1)) + goto err_ifinfo1; - if (WARN_ON(!ifinfo1 || !ifinfo2)) - return false; + ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); + if (WARN_ON(!ifinfo2)) + goto err_ifinfo2; threshold = ifinfo1->bat_v.throughput / 4; threshold = ifinfo1->bat_v.throughput - threshold; - return ifinfo2->bat_v.throughput > threshold; + ret = ifinfo2->bat_v.throughput > threshold; + + batadv_neigh_ifinfo_put(ifinfo2); +err_ifinfo2: + batadv_neigh_ifinfo_put(ifinfo1); +err_ifinfo1: + return ret; } static struct batadv_algo_ops batadv_batman_v __read_mostly = { -- cgit v0.10.2 From f7dcdf5fdbe8fec7670d8f65a5db595c98e0ecab Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Feb 2016 22:56:33 +0100 Subject: batman-adv: Fix unexpected free of bcast_own on add_if error The function batadv_iv_ogm_orig_add_if allocates new buffers for bcast_own and bcast_own_sum. It is expected that these buffers are unchanged in case either bcast_own or bcast_own_sum couldn't be resized. But the error handling of this function frees the already resized buffer for bcast_own when the allocation of the new bcast_own_sum buffer failed. This will lead to an invalid memory access when some code will try to access bcast_own. Instead the resized new bcast_own buffer has to be kept. This will not lead to problems because the size of the buffer was only increased and therefore no user of the buffer will try to access bytes outside of the new buffer. Fixes: d0015fdd3d2c ("batman-adv: provide orig_node routing API") Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 7f98a9d..1b5bbaf 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -157,10 +157,8 @@ static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, orig_node->bat_iv.bcast_own = data_ptr; data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC); - if (!data_ptr) { - kfree(orig_node->bat_iv.bcast_own); + if (!data_ptr) goto unlock; - } memcpy(data_ptr, orig_node->bat_iv.bcast_own_sum, (max_if_num - 1) * sizeof(u8)); -- cgit v0.10.2 From 1653f61d656516aae7130db19561258a847d1e94 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Mon, 2 May 2016 01:14:40 +0800 Subject: batman-adv: make sure ELP/OGM orig MAC is updated on address change When the MAC address of the primary interface is changed, update the originator address in the ELP and OGM skb buffers as well in order to reflect the change. Fixes: d6f94d91f766 ("batman-adv: ELP - adding basic infrastructure") Reported-by: Marek Lindner Signed-off-by: Antonio Quartulli diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index 4f626a6..31bc57e 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -73,16 +73,34 @@ static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface) batadv_v_elp_iface_disable(hard_iface); } -static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface) -{ -} - static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface) { batadv_v_elp_primary_iface_set(hard_iface); batadv_v_ogm_primary_iface_set(hard_iface); } +/** + * batadv_v_iface_update_mac - react to hard-interface MAC address change + * @hard_iface: the modified interface + * + * If the modified interface is the primary one, update the originator + * address in the ELP and OGM messages to reflect the new MAC address. + */ +static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface) +{ + struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); + struct batadv_hard_iface *primary_if; + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (primary_if != hard_iface) + goto out; + + batadv_v_primary_iface_set(hard_iface); +out: + if (primary_if) + batadv_hardif_put(primary_if); +} + static void batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh) { -- cgit v0.10.2 From d285f52cc0f23564fd61976d43fd5b991b4828f6 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 16 Feb 2016 10:47:07 +0100 Subject: batman-adv: Fix integer overflow in batadv_iv_ogm_calc_tq The undefined behavior sanatizer detected an signed integer overflow in a setup with near perfect link quality UBSAN: Undefined behaviour in net/batman-adv/bat_iv_ogm.c:1246:25 signed integer overflow: 8713350 * 255 cannot be represented in type 'int' The problems happens because the calculation of mixed unsigned and signed integers resulted in an integer multiplication. batadv_ogm_packet::tq (u8 255) * tq_own (u8 255) * tq_asym_penalty (int 134; max 255) * tq_iface_penalty (int 255; max 255) The tq_iface_penalty, tq_asym_penalty and inv_asym_penalty can just be changed to unsigned int because they are not expected to become negative. Fixes: c039876892e3 ("batman-adv: add WiFi penalty") Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 1b5bbaf..ce2f203 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -1180,9 +1180,10 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, u8 total_count; u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; - int tq_asym_penalty, inv_asym_penalty, if_num; + int if_num; + unsigned int tq_asym_penalty, inv_asym_penalty; unsigned int combined_tq; - int tq_iface_penalty; + unsigned int tq_iface_penalty; bool ret = false; /* find corresponding one hop neighbor */ -- cgit v0.10.2 From e123705e58bf171be8c6eb0902ebfb5d6ed255ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Thu, 7 Jan 2016 08:11:12 +0100 Subject: batman-adv: Avoid duplicate neigh_node additions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two parallel calls to batadv_neigh_node_new() might race for creating and adding the same neig_node. Fix this by including the check for any already existing, identical neigh_node within the spin-lock. This fixes splats like the following: [ 739.535069] ------------[ cut here ]------------ [ 739.535079] WARNING: CPU: 0 PID: 0 at /usr/src/batman-adv/git/batman-adv/net/batman-adv/bat_iv_ogm.c:1004 batadv_iv_ogm_process_per_outif+0xe3f/0xe60 [batman_adv]() [ 739.535092] too many matching neigh_nodes [ 739.535094] Modules linked in: dm_mod tun ip6table_filter ip6table_mangle ip6table_nat nf_nat_ipv6 ip6_tables xt_nat iptable_nat nf_nat_ipv4 nf_nat xt_TCPMSS xt_mark iptable_mangle xt_tcpudp xt_conntrack iptable_filter ip_tables x_tables ip_gre ip_tunnel gre bridge stp llc thermal_sys kvm_intel kvm crct10dif_pclmul crc32_pclmul sha256_ssse3 sha256_generic hmac drbg ansi_cprng aesni_intel aes_x86_64 lrw gf128mul glue_helper ablk_helper cryptd evdev pcspkr ip6_gre ip6_tunnel tunnel6 batman_adv(O) libcrc32c nf_conntrack_ipv6 nf_defrag_ipv6 nf_conntrack_ipv4 nf_defrag_ipv4 nf_conntrack autofs4 ext4 crc16 mbcache jbd2 xen_netfront xen_blkfront crc32c_intel [ 739.535177] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W O 4.2.0-0.bpo.1-amd64 #1 Debian 4.2.6-3~bpo8+2 [ 739.535186] 0000000000000000 ffffffffa013b050 ffffffff81554521 ffff88007d003c18 [ 739.535201] ffffffff8106fa01 0000000000000000 ffff8800047a087a ffff880079c3a000 [ 739.735602] ffff88007b82bf40 ffff88007bc2d1c0 ffffffff8106fa7a ffffffffa013aa8e [ 739.735624] Call Trace: [ 739.735639] [] ? dump_stack+0x40/0x50 [ 739.735677] [] ? warn_slowpath_common+0x81/0xb0 [ 739.735692] [] ? warn_slowpath_fmt+0x4a/0x50 [ 739.735715] [] ? batadv_iv_ogm_process_per_outif+0xe3f/0xe60 [batman_adv] [ 739.735740] [] ? batadv_iv_ogm_receive+0x363/0x380 [batman_adv] [ 739.735762] [] ? batadv_iv_ogm_receive+0x363/0x380 [batman_adv] [ 739.735783] [] ? __raw_callee_save___pv_queued_spin_unlock+0x11/0x20 [ 739.735804] [] ? batadv_batman_skb_recv+0xc9/0x110 [batman_adv] [ 739.735825] [] ? __netif_receive_skb_core+0x841/0x9a0 [ 739.735838] [] ? __raw_callee_save___pv_queued_spin_unlock+0x11/0x20 [ 739.735853] [] ? process_backlog+0xa1/0x140 [ 739.735864] [] ? net_rx_action+0x20a/0x320 [ 739.735878] [] ? __do_softirq+0x107/0x270 [ 739.735891] [] ? irq_exit+0x92/0xa0 [ 739.735905] [] ? xen_evtchn_do_upcall+0x31/0x40 [ 739.735924] [] ? xen_do_hypervisor_callback+0x1e/0x40 [ 739.735939] [] ? xen_hypercall_sched_op+0xa/0x20 [ 739.735965] [] ? xen_hypercall_sched_op+0xa/0x20 [ 739.735979] [] ? xen_safe_halt+0xc/0x20 [ 739.735991] [] ? default_idle+0x1c/0xa0 [ 739.736004] [] ? cpu_startup_entry+0x2eb/0x350 [ 739.736019] [] ? start_kernel+0x480/0x48b [ 739.736032] [] ? xen_start_kernel+0x507/0x511 [ 739.736048] ---[ end trace c106bb901244bc8c ]--- Fixes: f987ed6ebd99 ("batman-adv: protect neighbor list with rcu locks") Reported-by: Martin Weinelt Signed-off-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 1ff4ee4..7f51bc2 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -619,6 +619,8 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node, struct batadv_neigh_node *neigh_node; struct batadv_hardif_neigh_node *hardif_neigh = NULL; + spin_lock_bh(&orig_node->neigh_list_lock); + neigh_node = batadv_neigh_node_get(orig_node, hard_iface, neigh_addr); if (neigh_node) goto out; @@ -650,15 +652,15 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node, kref_init(&neigh_node->refcount); kref_get(&neigh_node->refcount); - spin_lock_bh(&orig_node->neigh_list_lock); hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); - spin_unlock_bh(&orig_node->neigh_list_lock); batadv_dbg(BATADV_DBG_BATMAN, orig_node->bat_priv, "Creating new neighbor %pM for orig_node %pM on interface %s\n", neigh_addr, orig_node->orig, hard_iface->net_dev->name); out: + spin_unlock_bh(&orig_node->neigh_list_lock); + if (hardif_neigh) batadv_hardif_neigh_put(hardif_neigh); return neigh_node; -- cgit v0.10.2 From ebe24cea95ab969f76f2922032f6c390fdc816f2 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Sat, 7 May 2016 19:54:17 +0800 Subject: batman-adv: initialize ELP orig address on secondary interfaces This fix prevents nodes to wrongly create a 00:00:00:00:00:00 originator which can potentially interfere with the rest of the neighbor statistics. Fixes: d6f94d91f766 ("batman-adv: ELP - adding basic infrastructure") Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index 31bc57e..0a12e5c 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -40,6 +40,16 @@ static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface) { + struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); + struct batadv_hard_iface *primary_if; + + primary_if = batadv_primary_if_get_selected(bat_priv); + + if (primary_if) { + batadv_v_elp_iface_activate(primary_if, hard_iface); + batadv_hardif_put(primary_if); + } + /* B.A.T.M.A.N. V does not use any queuing mechanism, therefore it can * set the interface as ACTIVE right away, without any risk of race * condition diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index 3844e7e..df42eb1 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -377,6 +377,27 @@ void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface) } /** + * batadv_v_elp_iface_activate - update the ELP buffer belonging to the given + * hard-interface + * @primary_iface: the new primary interface + * @hard_iface: interface holding the to-be-updated buffer + */ +void batadv_v_elp_iface_activate(struct batadv_hard_iface *primary_iface, + struct batadv_hard_iface *hard_iface) +{ + struct batadv_elp_packet *elp_packet; + struct sk_buff *skb; + + if (!hard_iface->bat_v.elp_skb) + return; + + skb = hard_iface->bat_v.elp_skb; + elp_packet = (struct batadv_elp_packet *)skb->data; + ether_addr_copy(elp_packet->orig, + primary_iface->net_dev->dev_addr); +} + +/** * batadv_v_elp_primary_iface_set - change internal data to reflect the new * primary interface * @primary_iface: the new primary interface @@ -384,8 +405,6 @@ void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface) void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface) { struct batadv_hard_iface *hard_iface; - struct batadv_elp_packet *elp_packet; - struct sk_buff *skb; /* update orig field of every elp iface belonging to this mesh */ rcu_read_lock(); @@ -393,13 +412,7 @@ void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface) if (primary_iface->soft_iface != hard_iface->soft_iface) continue; - if (!hard_iface->bat_v.elp_skb) - continue; - - skb = hard_iface->bat_v.elp_skb; - elp_packet = (struct batadv_elp_packet *)skb->data; - ether_addr_copy(elp_packet->orig, - primary_iface->net_dev->dev_addr); + batadv_v_elp_iface_activate(primary_iface, hard_iface); } rcu_read_unlock(); } diff --git a/net/batman-adv/bat_v_elp.h b/net/batman-adv/bat_v_elp.h index e95f1bc..cc130b2 100644 --- a/net/batman-adv/bat_v_elp.h +++ b/net/batman-adv/bat_v_elp.h @@ -25,6 +25,8 @@ struct work_struct; int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface); void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface); +void batadv_v_elp_iface_activate(struct batadv_hard_iface *primary_iface, + struct batadv_hard_iface *hard_iface); void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface); int batadv_v_elp_packet_recv(struct sk_buff *skb, struct batadv_hard_iface *if_incoming); -- cgit v0.10.2