[bug report] netvsc: use ERR_PTR to avoid dereference issues

Stephen Hemminger stephen at networkplumber.org
Tue Jul 10 23:05:17 UTC 2018


On Tue, 3 Jul 2018 15:01:42 +0300
Dan Carpenter <dan.carpenter at oracle.com> wrote:

> Hello stephen hemminger,
> 
> The patch 9749fed5d43d: "netvsc: use ERR_PTR to avoid dereference
> issues" from Jul 19, 2017, leads to the following static checker
> warning:
> 
> 	drivers/net/hyperv/rndis_filter.c:1344 rndis_filter_device_add()
> 	warn: passing zero to 'ERR_PTR'
> 
> drivers/net/hyperv/rndis_filter.c
>   1300          ret = rndis_filter_query_device(rndis_device, net_device,
>   1301                                          OID_GEN_RECEIVE_SCALE_CAPABILITIES,
>   1302                                          &rsscap, &rsscap_size);
>   1303          if (ret || rsscap.num_recv_que < 2)
>                            ^^^^^^^^^^^^^^^^^^^^^^^
> I think this used to be a success path, but now it leads to a NULL
> dereference in the caller.  I guess we should set "ret = -ENOMEM;" here?
> 
>   1304                  goto out;
>   1305  
>   1306          /* This guarantees that num_possible_rss_qs <= num_online_cpus */
>   1307          num_possible_rss_qs = min_t(u32, num_online_cpus(),
>   1308                                      rsscap.num_recv_que);
>   1309  
>   1310          net_device->max_chn = min_t(u32, VRSS_CHANNEL_MAX, num_possible_rss_qs);
>   1311  
>   1312          /* We will use the given number of channels if available. */
>   1313          net_device->num_chn = min(net_device->max_chn, device_info->num_chn);
>   1314  
>   1315          for (i = 0; i < ITAB_NUM; i++)
>   1316                  rndis_device->rx_table[i] = ethtool_rxfh_indir_default(
>   1317                                                  i, net_device->num_chn);
>   1318  
>   1319          atomic_set(&net_device->open_chn, 1);
>   1320          vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open);
>   1321  
>   1322          for (i = 1; i < net_device->num_chn; i++) {
>   1323                  ret = netvsc_alloc_recv_comp_ring(net_device, i);
>   1324                  if (ret) {
>   1325                          while (--i != 0)
>   1326                                  vfree(net_device->chan_table[i].mrc.slots);
>   1327                          goto out;
>   1328                  }
>   1329          }
>   1330  
>   1331          for (i = 1; i < net_device->num_chn; i++)
>   1332                  netif_napi_add(net, &net_device->chan_table[i].napi,
>   1333                                 netvsc_poll, NAPI_POLL_WEIGHT);
>   1334  
>   1335          return net_device;
>   1336  
>   1337  out:
>   1338          /* setting up multiple channels failed */
>   1339          net_device->max_chn = 1;
>   1340          net_device->num_chn = 1;
>   1341  
>   1342  err_dev_remv:
>   1343          rndis_filter_device_remove(dev, net_device);
S
>   1344          return ERR_PTR(ret);
> 
> regards,
> dan carpenter

It looks like there is a missing return after out:
all the fall throughs in that path should just work with single queue.
The current code would fail on old versions of Hyper-V.


This should be enough to fix the problem:

diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 9b4e3c3787e5..2a5209f23f29 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -1338,6 +1338,7 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
 	/* setting up multiple channels failed */
 	net_device->max_chn = 1;
 	net_device->num_chn = 1;
+	return net_device;
 
 err_dev_remv:
 	rndis_filter_device_remove(dev, net_device);





More information about the devel mailing list