diff options
author | stephen hemminger <stephen@networkplumber.org> | 2017-04-19 18:22:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-04-21 13:59:57 -0400 |
commit | 76bb5db5c749dfe19d779aac076133e821b859dd (patch) | |
tree | d844c765fe7dcdf2cafb136bcaa2f3cfb3569250 /drivers/net | |
parent | dfb05553a55d89e6daae9cb9abfdf4751e14d72d (diff) |
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')
-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) | |||
584 | /* Now, we can close the channel safely */ | 584 | /* Now, we can close the channel safely */ |
585 | vmbus_close(device->channel); | 585 | vmbus_close(device->channel); |
586 | 586 | ||
587 | /* And dissassociate NAPI context from device */ | ||
587 | for (i = 0; i < net_device->num_chn; i++) | 588 | for (i = 0; i < net_device->num_chn; i++) |
588 | napi_disable(&net_device->chan_table[i].napi); | 589 | netif_napi_del(&net_device->chan_table[i].napi); |
589 | 590 | ||
590 | /* Release all resources */ | 591 | /* Release all resources */ |
591 | free_netvsc_device_rcu(net_device); | 592 | free_netvsc_device_rcu(net_device); |
@@ -1320,8 +1321,6 @@ int netvsc_device_add(struct hv_device *device, | |||
1320 | struct netvsc_channel *nvchan = &net_device->chan_table[i]; | 1321 | struct netvsc_channel *nvchan = &net_device->chan_table[i]; |
1321 | 1322 | ||
1322 | nvchan->channel = device->channel; | 1323 | nvchan->channel = device->channel; |
1323 | netif_napi_add(ndev, &nvchan->napi, | ||
1324 | netvsc_poll, NAPI_POLL_WEIGHT); | ||
1325 | } | 1324 | } |
1326 | 1325 | ||
1327 | /* Open the channel */ | 1326 | /* Open the channel */ |
@@ -1339,6 +1338,8 @@ int netvsc_device_add(struct hv_device *device, | |||
1339 | netdev_dbg(ndev, "hv_netvsc channel opened successfully\n"); | 1338 | netdev_dbg(ndev, "hv_netvsc channel opened successfully\n"); |
1340 | 1339 | ||
1341 | /* Enable NAPI handler for init callbacks */ | 1340 | /* Enable NAPI handler for init callbacks */ |
1341 | netif_napi_add(ndev, &net_device->chan_table[0].napi, | ||
1342 | netvsc_poll, NAPI_POLL_WEIGHT); | ||
1342 | napi_enable(&net_device->chan_table[0].napi); | 1343 | napi_enable(&net_device->chan_table[0].napi); |
1343 | 1344 | ||
1344 | /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is | 1345 | /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is |
@@ -1357,7 +1358,7 @@ int netvsc_device_add(struct hv_device *device, | |||
1357 | return ret; | 1358 | return ret; |
1358 | 1359 | ||
1359 | close: | 1360 | close: |
1360 | napi_disable(&net_device->chan_table[0].napi); | 1361 | netif_napi_del(&net_device->chan_table[0].napi); |
1361 | 1362 | ||
1362 | /* Now, we can close the channel safely */ | 1363 | /* Now, we can close the channel safely */ |
1363 | vmbus_close(device->channel); | 1364 | 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) | |||
1009 | 1009 | ||
1010 | /* Set the channel before opening.*/ | 1010 | /* Set the channel before opening.*/ |
1011 | nvchan->channel = new_sc; | 1011 | nvchan->channel = new_sc; |
1012 | netif_napi_add(ndev, &nvchan->napi, | ||
1013 | netvsc_poll, NAPI_POLL_WEIGHT); | ||
1012 | 1014 | ||
1013 | ret = vmbus_open(new_sc, nvscdev->ring_size * PAGE_SIZE, | 1015 | ret = vmbus_open(new_sc, nvscdev->ring_size * PAGE_SIZE, |
1014 | nvscdev->ring_size * PAGE_SIZE, NULL, 0, | 1016 | nvscdev->ring_size * PAGE_SIZE, NULL, 0, |
1015 | netvsc_channel_cb, nvchan); | 1017 | netvsc_channel_cb, nvchan); |
1016 | 1018 | if (ret == 0) | |
1017 | 1019 | napi_enable(&nvchan->napi); | |
1018 | napi_enable(&nvchan->napi); | 1020 | else |
1021 | netdev_err(ndev, "sub channel open failed (%d)\n", ret); | ||
1019 | 1022 | ||
1020 | if (refcount_dec_and_test(&nvscdev->sc_offered)) | 1023 | if (refcount_dec_and_test(&nvscdev->sc_offered)) |
1021 | complete(&nvscdev->channel_init_wait); | 1024 | complete(&nvscdev->channel_init_wait); |