aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
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:04:46 -0700
commitd5bf240fa193989d605a715bda7cb3283b1abc89 (patch)
treea975ae3d030ec519d261e07dcd566faf6bcf638d /drivers/net
parent1d81283ce68fb5f6841aeea620a133e5f9707e33 (diff)
downloadkernel_samsung_smdk4412-d5bf240fa193989d605a715bda7cb3283b1abc89.zip
kernel_samsung_smdk4412-d5bf240fa193989d605a715bda7cb3283b1abc89.tar.gz
kernel_samsung_smdk4412-d5bf240fa193989d605a715bda7cb3283b1abc89.tar.bz2
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/net')
-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 735f726..4c0bdac 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -193,7 +193,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)
@@ -687,7 +688,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;
@@ -713,7 +714,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);