Merge tag 'batman-adv-fix-for-davem' of git://git.open-mesh.org/linux-merge
authorDavid S. Miller <davem@davemloft.net>
Thu, 28 Apr 2016 20:42:40 +0000 (16:42 -0400)
committerDavid S. Miller <davem@davemloft.net>
Thu, 28 Apr 2016 20:42:40 +0000 (16:42 -0400)
Antonio Quartulli says:

====================
In this patchset you can find the following fixes:

1) check skb size to avoid reading beyond its border when delivering
   payloads, by Sven Eckelmann
2) initialize last_seen time in neigh_node object to prevent cleanup
   routine from accidentally purge it, by Marek Lindner
3) release "recently added" slave interfaces upon virtual/batman
   interface shutdown, by Sven Eckelmann
4) properly decrease router object reference counter upon routing table
   update, by Sven Eckelmann
5) release queue slots when purging OGM packets of deactivating slave
   interface, by Linus Lüssing

Patch 2 and 3 have no "Fixes:" tag because the offending commits date
back to when batman-adv was not yet officially in the net tree.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
net/batman-adv/hard-interface.c
net/batman-adv/originator.c
net/batman-adv/routing.c
net/batman-adv/send.c
net/batman-adv/soft-interface.c

index b22b2775a0a5ff706c17ea06c39c9bb092da1f9a..c61d5b0b24d27be7d9d962cb4b15de890fed1803 100644 (file)
@@ -572,8 +572,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
        struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
        struct batadv_hard_iface *primary_if = NULL;
 
-       if (hard_iface->if_status == BATADV_IF_ACTIVE)
-               batadv_hardif_deactivate_interface(hard_iface);
+       batadv_hardif_deactivate_interface(hard_iface);
 
        if (hard_iface->if_status != BATADV_IF_INACTIVE)
                goto out;
index e4cbb0753e37ff6681a20e8912df1f4ad1e74a05..d52f67a0c057230b4b1dfa66d43594d7f30625ee 100644 (file)
@@ -663,6 +663,7 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
        ether_addr_copy(neigh_node->addr, neigh_addr);
        neigh_node->if_incoming = hard_iface;
        neigh_node->orig_node = orig_node;
+       neigh_node->last_seen = jiffies;
 
        /* extra reference for return */
        kref_init(&neigh_node->refcount);
index 4dd646a52f1a16ca297a3cdb1abeff56206df166..b781bf75325061a5157c54bc976d1df1a522e0bd 100644 (file)
@@ -105,6 +105,15 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
                neigh_node = NULL;
 
        spin_lock_bh(&orig_node->neigh_list_lock);
+       /* curr_router used earlier may not be the current orig_ifinfo->router
+        * anymore because it was dereferenced outside of the neigh_list_lock
+        * protected region. After the new best neighbor has replace the current
+        * best neighbor the reference counter needs to decrease. Consequently,
+        * the code needs to ensure the curr_router variable contains a pointer
+        * to the replaced best neighbor.
+        */
+       curr_router = rcu_dereference_protected(orig_ifinfo->router, true);
+
        rcu_assign_pointer(orig_ifinfo->router, neigh_node);
        spin_unlock_bh(&orig_node->neigh_list_lock);
        batadv_orig_ifinfo_put(orig_ifinfo);
index 3ce06e0a91b1c125cdf5ff594db57529a2deaacf..76417850d3fcbb6ddf5d6f15c822cebdda4912da 100644 (file)
@@ -675,6 +675,9 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
 
                if (pending) {
                        hlist_del(&forw_packet->list);
+                       if (!forw_packet->own)
+                               atomic_inc(&bat_priv->bcast_queue_left);
+
                        batadv_forw_packet_free(forw_packet);
                }
        }
@@ -702,6 +705,9 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
 
                if (pending) {
                        hlist_del(&forw_packet->list);
+                       if (!forw_packet->own)
+                               atomic_inc(&bat_priv->batman_queue_left);
+
                        batadv_forw_packet_free(forw_packet);
                }
        }
index 0710379491bffc0627c35f0ed5ba6bbf535bb1bb..8a136b6a1ff06165b7e7c257fd8b00847fbf3065 100644 (file)
@@ -408,11 +408,17 @@ void batadv_interface_rx(struct net_device *soft_iface,
         */
        nf_reset(skb);
 
+       if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
+               goto dropped;
+
        vid = batadv_get_vid(skb, 0);
        ethhdr = eth_hdr(skb);
 
        switch (ntohs(ethhdr->h_proto)) {
        case ETH_P_8021Q:
+               if (!pskb_may_pull(skb, VLAN_ETH_HLEN))
+                       goto dropped;
+
                vhdr = (struct vlan_ethhdr *)skb->data;
 
                if (vhdr->h_vlan_encapsulated_proto != ethertype)
@@ -424,8 +430,6 @@ void batadv_interface_rx(struct net_device *soft_iface,
        }
 
        /* skb->dev & skb->pkt_type are set here */
-       if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
-               goto dropped;
        skb->protocol = eth_type_trans(skb, soft_iface);
 
        /* should not be necessary anymore as we use skb_pull_rcsum()