linux_dsm_epyc7002/drivers/net/usb
Eugene Shatokhin fcb0bb6aab usbnet: Fix a race between usbnet_stop() and the BH
The race may happen when a device (e.g. YOTA 4G LTE Modem) is
unplugged while the system is downloading a large file from the Net.

Hardware breakpoints and Kprobes with delays were used to confirm that
the race does actually happen.

The race is on skb_queue ('next' pointer) between usbnet_stop()
and rx_complete(), which, in turn, calls usbnet_bh().

Here is a part of the call stack with the code where the changes to the
queue happen. The line numbers are for the kernel 4.1.0:

*0 __skb_unlink (skbuff.h:1517)
    prev->next = next;
*1 defer_bh (usbnet.c:430)
    spin_lock_irqsave(&list->lock, flags);
    old_state = entry->state;
    entry->state = state;
    __skb_unlink(skb, list);
    spin_unlock(&list->lock);
    spin_lock(&dev->done.lock);
    __skb_queue_tail(&dev->done, skb);
    if (dev->done.qlen == 1)
        tasklet_schedule(&dev->bh);
    spin_unlock_irqrestore(&dev->done.lock, flags);
*2 rx_complete (usbnet.c:640)
    state = defer_bh(dev, skb, &dev->rxq, state);

At the same time, the following code repeatedly checks if the queue is
empty and reads these values concurrently with the above changes:

*0  usbnet_terminate_urbs (usbnet.c:765)
    /* maybe wait for deletions to finish. */
    while (!skb_queue_empty(&dev->rxq)
        && !skb_queue_empty(&dev->txq)
        && !skb_queue_empty(&dev->done)) {
            schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
            set_current_state(TASK_UNINTERRUPTIBLE);
            netif_dbg(dev, ifdown, dev->net,
                  "waited for %d urb completions\n", temp);
    }
*1  usbnet_stop (usbnet.c:806)
    if (!(info->flags & FLAG_AVOID_UNLINK_URBS))
        usbnet_terminate_urbs(dev);

As a result, it is possible, for example, that the skb is removed from
dev->rxq by __skb_unlink() before the check
"!skb_queue_empty(&dev->rxq)" in usbnet_terminate_urbs() is made. It is
also possible in this case that the skb is added to dev->done queue
after "!skb_queue_empty(&dev->done)" is checked. So
usbnet_terminate_urbs() may stop waiting and return while dev->done
queue still has an item.

Locking in defer_bh() and usbnet_terminate_urbs() was revisited to avoid
this race.

Signed-off-by: Eugene Shatokhin <eugene.shatokhin@rosalab.ru>
Reviewed-by: Bjørn Mork <bjorn@mork.no>
Acked-by: Oliver Neukum <oneukum@suse.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-09-08 13:17:43 -07:00
..
asix_common.c usbnet: Fix tx_bytes statistic running backward in cdc_ncm 2015-03-29 12:06:45 -07:00
asix_devices.c
asix.h
ax88172a.c
ax88179_178a.c
catc.c
cdc_eem.c
cdc_ether.c drivers/net/usb: add device id for NVIDIA Tegra USB 3.0 Ethernet 2015-07-08 23:58:20 -07:00
cdc_mbim.c cdc_ncm: Add support for moving NDP to end of NCM frame 2015-07-09 14:58:31 -07:00
cdc_ncm.c cdc_ncm: update specs URL 2015-07-11 21:12:23 -07:00
cdc_subset.c
cdc-phonet.c
cx82310_eth.c cx82310_eth: fix semicolon.cocci warnings 2015-03-24 14:56:02 -04:00
dm9601.c
gl620a.c
hso.c
huawei_cdc_ncm.c cdc_ncm: Add support for moving NDP to end of NCM frame 2015-07-09 14:58:31 -07:00
int51x1.c
ipheth.c
kalmia.c
kaweth.c
Kconfig Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver 2015-07-31 15:19:00 -07:00
lan78xx.c lan78xx: Fix ladv/radv error handling in lan78xx_link_reset() 2015-09-06 19:46:56 -07:00
lan78xx.h Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver 2015-07-31 15:19:00 -07:00
lg-vl600.c
Makefile Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver 2015-07-31 15:19:00 -07:00
mcs7830.c
net1080.c
pegasus.c
pegasus.h
plusb.c
qmi_wwan.c net: qmi_wwan: Sierra Wireless MC73xx -> Sierra Wireless MC7304/MC7354 2015-08-31 15:16:17 -07:00
r8152.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2015-07-31 23:52:20 -07:00
rndis_host.c
rtl8150.c
sierra_net.c
smsc75xx.c
smsc75xx.h
smsc95xx.c
smsc95xx.h
sr9700.c
sr9700.h
sr9800.c usbnet: Fix tx_bytes statistic running backward in cdc_ncm 2015-03-29 12:06:45 -07:00
sr9800.h
usbnet.c usbnet: Fix a race between usbnet_stop() and the BH 2015-09-08 13:17:43 -07:00
zaurus.c