Commit 29d1441d authored by David S. Miller's avatar David S. Miller

Merge tag 'batman-adv-fix-for-davem' of git://git.open-mesh.org/linux-merge

Antonio Quartulli says:

====================
Two of the fixes included in this patchset prevent wrong memory
access - it was triggered when removing an object from a list
after it was already free'd due to bad reference counting.
This misbehaviour existed for both the gw_node and the
orig_node_vlan object and has been fixed by Sven Eckelmann.

The last patch fixes our interface feasibility check and prevents
it from looping indefinitely when two net_device objects
reference each other via iflink index (i.e. veth pair), by
Andrew Lunn
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a97eb33f 1bc4e2b0
...@@ -527,11 +527,12 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv, ...@@ -527,11 +527,12 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv,
* gets dereferenced. * gets dereferenced.
*/ */
spin_lock_bh(&bat_priv->gw.list_lock); spin_lock_bh(&bat_priv->gw.list_lock);
hlist_del_init_rcu(&gw_node->list); if (!hlist_unhashed(&gw_node->list)) {
hlist_del_init_rcu(&gw_node->list);
batadv_gw_node_free_ref(gw_node);
}
spin_unlock_bh(&bat_priv->gw.list_lock); spin_unlock_bh(&bat_priv->gw.list_lock);
batadv_gw_node_free_ref(gw_node);
curr_gw = batadv_gw_get_selected_gw_node(bat_priv); curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
if (gw_node == curr_gw) if (gw_node == curr_gw)
batadv_gw_reselect(bat_priv); batadv_gw_reselect(bat_priv);
......
...@@ -75,6 +75,28 @@ batadv_hardif_get_by_netdev(const struct net_device *net_dev) ...@@ -75,6 +75,28 @@ batadv_hardif_get_by_netdev(const struct net_device *net_dev)
return hard_iface; return hard_iface;
} }
/**
* batadv_mutual_parents - check if two devices are each others parent
* @dev1: 1st net_device
* @dev2: 2nd net_device
*
* veth devices come in pairs and each is the parent of the other!
*
* Return: true if the devices are each others parent, otherwise false
*/
static bool batadv_mutual_parents(const struct net_device *dev1,
const struct net_device *dev2)
{
int dev1_parent_iflink = dev_get_iflink(dev1);
int dev2_parent_iflink = dev_get_iflink(dev2);
if (!dev1_parent_iflink || !dev2_parent_iflink)
return false;
return (dev1_parent_iflink == dev2->ifindex) &&
(dev2_parent_iflink == dev1->ifindex);
}
/** /**
* batadv_is_on_batman_iface - check if a device is a batman iface descendant * batadv_is_on_batman_iface - check if a device is a batman iface descendant
* @net_dev: the device to check * @net_dev: the device to check
...@@ -108,6 +130,9 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) ...@@ -108,6 +130,9 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
if (WARN(!parent_dev, "Cannot find parent device")) if (WARN(!parent_dev, "Cannot find parent device"))
return false; return false;
if (batadv_mutual_parents(net_dev, parent_dev))
return false;
ret = batadv_is_on_batman_iface(parent_dev); ret = batadv_is_on_batman_iface(parent_dev);
return ret; return ret;
......
...@@ -303,9 +303,11 @@ static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node, ...@@ -303,9 +303,11 @@ static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node,
if (atomic_add_return(v, &vlan->tt.num_entries) == 0) { if (atomic_add_return(v, &vlan->tt.num_entries) == 0) {
spin_lock_bh(&orig_node->vlan_list_lock); spin_lock_bh(&orig_node->vlan_list_lock);
hlist_del_init_rcu(&vlan->list); if (!hlist_unhashed(&vlan->list)) {
hlist_del_init_rcu(&vlan->list);
batadv_orig_node_vlan_free_ref(vlan);
}
spin_unlock_bh(&orig_node->vlan_list_lock); spin_unlock_bh(&orig_node->vlan_list_lock);
batadv_orig_node_vlan_free_ref(vlan);
} }
batadv_orig_node_vlan_free_ref(vlan); batadv_orig_node_vlan_free_ref(vlan);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment