diff options
author | David Vrabel <david.vrabel@citrix.com> | 2015-05-27 10:46:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-05-27 14:02:28 -0400 |
commit | ad0681185770716523c81b156c44b9804d7b8ed2 (patch) | |
tree | f2519cc3625d8d327a5e4eb8e7ca15ed4fd83274 /drivers/net/xen-netfront.c | |
parent | f4ecf29fd78d19a9301e638eaa1419e5c8fbdce1 (diff) |
xen-netfront: properly destroy queues when removing device
xennet_remove() freed the queues before freeing the netdevice which
results in a use-after-free when free_netdev() tries to delete the
napi instances that have already been freed.
Fix this by fully destroy the queues (which includes deleting the napi
instances) before freeing the netdevice.
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/xen-netfront.c')
-rw-r--r-- | drivers/net/xen-netfront.c | 15 |
1 files changed, 2 insertions, 13 deletions
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 3f45afd4382e..e031c943286e 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c | |||
@@ -1698,6 +1698,7 @@ static void xennet_destroy_queues(struct netfront_info *info) | |||
1698 | 1698 | ||
1699 | if (netif_running(info->netdev)) | 1699 | if (netif_running(info->netdev)) |
1700 | napi_disable(&queue->napi); | 1700 | napi_disable(&queue->napi); |
1701 | del_timer_sync(&queue->rx_refill_timer); | ||
1701 | netif_napi_del(&queue->napi); | 1702 | netif_napi_del(&queue->napi); |
1702 | } | 1703 | } |
1703 | 1704 | ||
@@ -2102,9 +2103,6 @@ static const struct attribute_group xennet_dev_group = { | |||
2102 | static int xennet_remove(struct xenbus_device *dev) | 2103 | static int xennet_remove(struct xenbus_device *dev) |
2103 | { | 2104 | { |
2104 | struct netfront_info *info = dev_get_drvdata(&dev->dev); | 2105 | struct netfront_info *info = dev_get_drvdata(&dev->dev); |
2105 | unsigned int num_queues = info->netdev->real_num_tx_queues; | ||
2106 | struct netfront_queue *queue = NULL; | ||
2107 | unsigned int i = 0; | ||
2108 | 2106 | ||
2109 | dev_dbg(&dev->dev, "%s\n", dev->nodename); | 2107 | dev_dbg(&dev->dev, "%s\n", dev->nodename); |
2110 | 2108 | ||
@@ -2112,16 +2110,7 @@ static int xennet_remove(struct xenbus_device *dev) | |||
2112 | 2110 | ||
2113 | unregister_netdev(info->netdev); | 2111 | unregister_netdev(info->netdev); |
2114 | 2112 | ||
2115 | for (i = 0; i < num_queues; ++i) { | 2113 | xennet_destroy_queues(info); |
2116 | queue = &info->queues[i]; | ||
2117 | del_timer_sync(&queue->rx_refill_timer); | ||
2118 | } | ||
2119 | |||
2120 | if (num_queues) { | ||
2121 | kfree(info->queues); | ||
2122 | info->queues = NULL; | ||
2123 | } | ||
2124 | |||
2125 | xennet_free_netdev(info->netdev); | 2114 | xennet_free_netdev(info->netdev); |
2126 | 2115 | ||
2127 | return 0; | 2116 | return 0; |