mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									dfb05553a5
								
							
						
					
					
						commit
						76bb5db5c7
					
				
					 2 changed files with 11 additions and 7 deletions
				
			
		| 
						 | 
					@ -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,
 | 
				
			||||||
		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,
 | 
				
			||||||
	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,
 | 
				
			||||||
	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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue