summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2013-05-09 04:23:40 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-05-19 10:54:47 -0700
commitf2f17ef7c7a9ac2a9ed1160c768c67d2cf86b8d5 (patch)
treed30412dc090b30800365582acba0f0f11924b2b4 /drivers
parente52507b9069411a0a770d49daa246f8cb2fbcde4 (diff)
downloadlinux-3.10-f2f17ef7c7a9ac2a9ed1160c768c67d2cf86b8d5.tar.gz
linux-3.10-f2f17ef7c7a9ac2a9ed1160c768c67d2cf86b8d5.tar.bz2
linux-3.10-f2f17ef7c7a9ac2a9ed1160c768c67d2cf86b8d5.zip
macvlan: fix passthru mode race between dev removal and rx path
[ Upstream commit 233c7df0821c4190e2d3f4be0f2ca0ab40a5ed8c, 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: commit eb06acdc85585f2 "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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/macvlan.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 956a5ed8790..71605231bcb 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -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);