diff options
author | stephen hemminger <stephen@networkplumber.org> | 2017-04-20 01:22:02 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-04-21 20:59:57 +0300 |
commit | 76bb5db5c749dfe19d779aac076133e821b859dd (patch) | |
tree | d844c765fe7dcdf2cafb136bcaa2f3cfb3569250 /drivers/net/hyperv | |
parent | dfb05553a55d89e6daae9cb9abfdf4751e14d72d (diff) | |
download | linux-76bb5db5c749dfe19d779aac076133e821b859dd.tar.xz |
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: Stephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/hyperv')
-rw-r--r-- | drivers/net/hyperv/netvsc.c | 9 | ||||
-rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 9 |
2 files changed, 11 insertions, 7 deletions
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 967843ba03fa..f99651c03e0a 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -584,8 +584,9 @@ void netvsc_device_remove(struct hv_device *device) /* Now, we can close the channel safely */ vmbus_close(device->channel); + /* And dissassociate NAPI context from device */ 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 */ free_netvsc_device_rcu(net_device); @@ -1320,8 +1321,6 @@ int netvsc_device_add(struct hv_device *device, struct netvsc_channel *nvchan = &net_device->chan_table[i]; nvchan->channel = device->channel; - netif_napi_add(ndev, &nvchan->napi, - netvsc_poll, NAPI_POLL_WEIGHT); } /* Open the channel */ @@ -1339,6 +1338,8 @@ int netvsc_device_add(struct hv_device *device, netdev_dbg(ndev, "hv_netvsc channel opened successfully\n"); /* 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); /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is @@ -1357,7 +1358,7 @@ int netvsc_device_add(struct hv_device *device, return ret; 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 */ vmbus_close(device->channel); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 1e9445bc4539..ab92c3c95951 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1009,13 +1009,16 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc) /* Set the channel before opening.*/ 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, nvscdev->ring_size * PAGE_SIZE, NULL, 0, netvsc_channel_cb, nvchan); - - - napi_enable(&nvchan->napi); + if (ret == 0) + napi_enable(&nvchan->napi); + else + netdev_err(ndev, "sub channel open failed (%d)\n", ret); if (refcount_dec_and_test(&nvscdev->sc_offered)) complete(&nvscdev->channel_init_wait); |