Commit 76bb5db5 authored by stephen hemminger's avatar stephen hemminger Committed by David S. Miller

netvsc: fix use after free on module removal

The NAPI data structure is embedded in the netvsc_device structure
and is freed when device is closed. There is still a reference
(in NAPI list) to this which causes a crash in netif_napi_del
when device is removed. Fix by managing NAPI instances correctly.
Signed-off-by: default avatarStephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dfb05553
...@@ -584,8 +584,9 @@ void netvsc_device_remove(struct hv_device *device) ...@@ -584,8 +584,9 @@ void netvsc_device_remove(struct hv_device *device)
/* Now, we can close the channel safely */ /* Now, we can close the channel safely */
vmbus_close(device->channel); vmbus_close(device->channel);
/* And dissassociate NAPI context from device */
for (i = 0; i < net_device->num_chn; i++) for (i = 0; i < net_device->num_chn; i++)
napi_disable(&net_device->chan_table[i].napi); netif_napi_del(&net_device->chan_table[i].napi);
/* Release all resources */ /* Release all resources */
free_netvsc_device_rcu(net_device); free_netvsc_device_rcu(net_device);
...@@ -1320,8 +1321,6 @@ int netvsc_device_add(struct hv_device *device, ...@@ -1320,8 +1321,6 @@ int netvsc_device_add(struct hv_device *device,
struct netvsc_channel *nvchan = &net_device->chan_table[i]; struct netvsc_channel *nvchan = &net_device->chan_table[i];
nvchan->channel = device->channel; nvchan->channel = device->channel;
netif_napi_add(ndev, &nvchan->napi,
netvsc_poll, NAPI_POLL_WEIGHT);
} }
/* Open the channel */ /* Open the channel */
...@@ -1339,6 +1338,8 @@ int netvsc_device_add(struct hv_device *device, ...@@ -1339,6 +1338,8 @@ int netvsc_device_add(struct hv_device *device,
netdev_dbg(ndev, "hv_netvsc channel opened successfully\n"); netdev_dbg(ndev, "hv_netvsc channel opened successfully\n");
/* Enable NAPI handler for init callbacks */ /* Enable NAPI handler for init callbacks */
netif_napi_add(ndev, &net_device->chan_table[0].napi,
netvsc_poll, NAPI_POLL_WEIGHT);
napi_enable(&net_device->chan_table[0].napi); napi_enable(&net_device->chan_table[0].napi);
/* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is
...@@ -1357,7 +1358,7 @@ int netvsc_device_add(struct hv_device *device, ...@@ -1357,7 +1358,7 @@ int netvsc_device_add(struct hv_device *device,
return ret; return ret;
close: close:
napi_disable(&net_device->chan_table[0].napi); netif_napi_del(&net_device->chan_table[0].napi);
/* Now, we can close the channel safely */ /* Now, we can close the channel safely */
vmbus_close(device->channel); vmbus_close(device->channel);
......
...@@ -1009,13 +1009,16 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc) ...@@ -1009,13 +1009,16 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc)
/* Set the channel before opening.*/ /* Set the channel before opening.*/
nvchan->channel = new_sc; nvchan->channel = new_sc;
netif_napi_add(ndev, &nvchan->napi,
netvsc_poll, NAPI_POLL_WEIGHT);
ret = vmbus_open(new_sc, nvscdev->ring_size * PAGE_SIZE, ret = vmbus_open(new_sc, nvscdev->ring_size * PAGE_SIZE,
nvscdev->ring_size * PAGE_SIZE, NULL, 0, nvscdev->ring_size * PAGE_SIZE, NULL, 0,
netvsc_channel_cb, nvchan); netvsc_channel_cb, nvchan);
if (ret == 0)
napi_enable(&nvchan->napi);
napi_enable(&nvchan->napi); else
netdev_err(ndev, "sub channel open failed (%d)\n", ret);
if (refcount_dec_and_test(&nvscdev->sc_offered)) if (refcount_dec_and_test(&nvscdev->sc_offered))
complete(&nvscdev->channel_init_wait); complete(&nvscdev->channel_init_wait);
......
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