mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
macvlan: fix passthru mode race between dev removal and rx path
[ Upstream commit233c7df082
, note that I had to add list_first_or_null_rcu to rculist.h in order to accomodate this fix. ] Currently, if macvlan in passthru mode is created and data are rxed and you remove this device, following panic happens: NULL pointer dereference at 0000000000000198 IP: [<ffffffffa0196058>] macvlan_handle_frame+0x153/0x1f7 [macvlan] I'm using following script to trigger this: <script> while [ 1 ] do ip link add link e1 name macvtap0 type macvtap mode passthru ip link set e1 up ip link set macvtap0 up IFINDEX=`ip link |grep macvtap0 | cut -f 1 -d ':'` cat /dev/tap$IFINDEX >/dev/null & ip link del dev macvtap0 done </script> I run this script while "ping -f" is running on another machine to send packets to e1 rx. Reason of the panic is that list_first_entry() is blindly called in macvlan_handle_frame() even if the list was empty. vlan is set to incorrect pointer which leads to the crash. I'm fixing this by protecting port->vlans list by rcu and by preventing from getting incorrect pointer in case the list is empty. Introduced by: commiteb06acdc85
"macvlan: Introduce 'passthru' mode to takeover the underlying device" Signed-off-by: Jiri Pirko <jiri@resnulli.us> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
e52507b906
commit
f2f17ef7c7
2 changed files with 21 additions and 3 deletions
|
@ -205,7 +205,8 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
|
|||
}
|
||||
|
||||
if (port->passthru)
|
||||
vlan = list_first_entry(&port->vlans, struct macvlan_dev, list);
|
||||
vlan = list_first_or_null_rcu(&port->vlans,
|
||||
struct macvlan_dev, list);
|
||||
else
|
||||
vlan = macvlan_hash_lookup(port, eth->h_dest);
|
||||
if (vlan == NULL)
|
||||
|
@ -724,7 +725,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
|
|||
if (err < 0)
|
||||
goto destroy_port;
|
||||
|
||||
list_add_tail(&vlan->list, &port->vlans);
|
||||
list_add_tail_rcu(&vlan->list, &port->vlans);
|
||||
netif_stacked_transfer_operstate(lowerdev, dev);
|
||||
|
||||
return 0;
|
||||
|
@ -750,7 +751,7 @@ void macvlan_dellink(struct net_device *dev, struct list_head *head)
|
|||
{
|
||||
struct macvlan_dev *vlan = netdev_priv(dev);
|
||||
|
||||
list_del(&vlan->list);
|
||||
list_del_rcu(&vlan->list);
|
||||
unregister_netdevice_queue(dev, head);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(macvlan_dellink);
|
||||
|
|
|
@ -241,6 +241,23 @@ static inline void list_splice_init_rcu(struct list_head *list,
|
|||
#define list_first_entry_rcu(ptr, type, member) \
|
||||
list_entry_rcu((ptr)->next, type, member)
|
||||
|
||||
/**
|
||||
* list_first_or_null_rcu - get the first element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Note that if the list is empty, it returns NULL.
|
||||
*
|
||||
* This primitive may safely run concurrently with the _rcu list-mutation
|
||||
* primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
|
||||
*/
|
||||
#define list_first_or_null_rcu(ptr, type, member) \
|
||||
({struct list_head *__ptr = (ptr); \
|
||||
struct list_head __rcu *__next = list_next_rcu(__ptr); \
|
||||
likely(__ptr != __next) ? container_of(__next, type, member) : NULL; \
|
||||
})
|
||||
|
||||
/**
|
||||
* list_for_each_entry_rcu - iterate over rcu list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
|
|
Loading…
Reference in a new issue