]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
netvsc: fix use after free on module removal
authorstephen hemminger <stephen@networkplumber.org>
Wed, 19 Apr 2017 22:22:02 +0000 (15:22 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 21 Apr 2017 17:59:57 +0000 (13:59 -0400)
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>
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/rndis_filter.c

index 967843ba03fa41d5cb2c9a46c5c5e3d6e5a3ff51..f99651c03e0a3612cdf89acd2d8302e1732a3338 100644 (file)
@@ -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);
index 1e9445bc45391195a9f15fbda7bf56fa2d3b762e..ab92c3c9595178c6e8ca47c332d153f79bd38672 100644 (file)
@@ -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);