summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@google.com>2020-10-29 10:15:51 +0100
committerGreg Kroah-Hartman <gregkh@google.com>2020-10-29 10:15:51 +0100
commit608df7b5d6267a4bb674dea62cacc4028f876784 (patch)
treea64328e82aeb938477d8621751ad86a4b5aa8c5c /drivers/usb
parent7a9986e91f90994623e4c5de1effce14729dba96 (diff)
parent8dfc31cb1f532f20ae71ca049a84c40226f30753 (diff)
Merge 4.4.241 into android-4.4-p
Changes in 4.4.241 ibmveth: Identify ingress large send packets. tipc: fix the skb_unshare() in tipc_buf_append() net/ipv4: always honour route mtu during forwarding r8169: fix data corruption issue on RTL8402 ALSA: bebob: potential info leak in hwdep_read() mm/kasan: print name of mem[set,cpy,move]() caller in report mm/kasan: add API to check memory regions compiler.h, kasan: Avoid duplicating __read_once_size_nocheck() compiler.h: Add read_word_at_a_time() function. lib/strscpy: Shut up KASAN false-positives in strscpy() x86/mm/ptdump: Fix soft lockup in page table walker net: hdlc: In hdlc_rcv, check to make sure dev is an HDLC device net: hdlc_raw_eth: Clear the IFF_TX_SKB_SHARING flag after calling ether_setup nfc: Ensure presence of NFC_ATTR_FIRMWARE_NAME attribute in nfc_genl_fw_download() tcp: fix to update snd_wl1 in bulk receiver fast path icmp: randomize the global rate limiter cifs: remove bogus debug code ima: Don't ignore errors from crypto_shash_update() EDAC/i5100: Fix error handling order in i5100_init_one() crypto: ixp4xx - Fix the size used in a 'dma_free_coherent()' call media: Revert "media: exynos4-is: Add missed check for pinctrl_lookup_state()" media: m5mols: Check function pointer in m5mols_sensor_power media: omap3isp: Fix memleak in isp_probe crypto: omap-sham - fix digcnt register handling with export/import media: tc358743: initialize variable media: ti-vpe: Fix a missing check and reference count leak ath6kl: prevent potential array overflow in ath6kl_add_new_sta() ath9k: Fix potential out of bounds in ath9k_htc_txcompletion_cb() wcn36xx: Fix reported 802.11n rx_highest rate wcn3660/wcn3680 mwifiex: Do not use GFP_KERNEL in atomic context drm/gma500: fix error check scsi: qla4xxx: Fix an error handling path in 'qla4xxx_get_host_stats()' scsi: csiostor: Fix wrong return value in csio_hw_prep_fw() backlight: sky81452-backlight: Fix refcount imbalance on error VMCI: check return value of get_user_pages_fast() for errors tty: serial: earlycon dependency tty: hvcs: Don't NULL tty->driver_data until hvcs_cleanup() pty: do tty_flip_buffer_push without port->lock in pty_write drivers/virt/fsl_hypervisor: Fix error handling path video: fbdev: vga16fb: fix setting of pixclock because a pass-by-value error video: fbdev: sis: fix null ptr dereference HID: roccat: add bounds checking in kone_sysfs_write_settings() ath6kl: wmi: prevent a shift wrapping bug in ath6kl_wmi_delete_pstream_cmd() misc: mic: scif: Fix error handling path ALSA: seq: oss: Avoid mutex lock for a long-time ioctl quota: clear padding in v2r1_mem2diskdqb() net: enic: Cure the enic api locking trainwreck mfd: sm501: Fix leaks in probe() usb: gadget: u_ether: enable qmult on SuperSpeed Plus as well nl80211: fix non-split wiphy information mwifiex: fix double free net: korina: fix kfree of rx/tx descriptor array IB/mlx4: Adjust delayed work when a dup is observed powerpc/pseries: Fix missing of_node_put() in rng_init() powerpc/icp-hv: Fix missing of_node_put() in success path mtd: lpddr: fix excessive stack usage with clang mtd: mtdoops: Don't write panic data twice ARM: 9007/1: l2c: fix prefetch bits init in L2X0_AUX_CTRL using DT values powerpc/tau: Use appropriate temperature sample interval powerpc/tau: Remove duplicated set_thresholds() call powerpc/tau: Disable TAU between measurements perf intel-pt: Fix "context_switch event has no tid" error kdb: Fix pager search for multi-line strings powerpc/perf/hv-gpci: Fix starting index value cpufreq: powernv: Fix frame-size-overflow in powernv_cpufreq_reboot_notifier lib/crc32.c: fix trivial typo in preprocessor condition vfio/pci: Clear token on bypass registration failure Input: imx6ul_tsc - clean up some errors in imx6ul_tsc_resume() Input: ep93xx_keypad - fix handling of platform_get_irq() error Input: omap4-keypad - fix handling of platform_get_irq() error Input: sun4i-ps2 - fix handling of platform_get_irq() error KVM: x86: emulating RDPID failure shall return #UD rather than #GP memory: omap-gpmc: Fix a couple off by ones memory: fsl-corenet-cf: Fix handling of platform_get_irq() error arm64: dts: zynqmp: Remove additional compatible string for i2c IPs powerpc/powernv/dump: Fix race while processing OPAL dump media: firewire: fix memory leak media: ati_remote: sanity check for both endpoints media: exynos4-is: Fix several reference count leaks due to pm_runtime_get_sync media: exynos4-is: Fix a reference count leak due to pm_runtime_get_sync media: exynos4-is: Fix a reference count leak media: bdisp: Fix runtime PM imbalance on error media: media/pci: prevent memory leak in bttv_probe media: uvcvideo: Ensure all probed info is returned to v4l2 mmc: sdio: Check for CISTPL_VERS_1 buffer size media: saa7134: avoid a shift overflow ntfs: add check for mft record size in superblock PM: hibernate: remove the bogus call to get_gendisk() in software_resume() scsi: mvumi: Fix error return in mvumi_io_attach() scsi: target: core: Add CONTROL field for trace events usb: gadget: function: printer: fix use-after-free in __lock_acquire udf: Limit sparing table size udf: Avoid accessing uninitialized data on failed inode read ath9k: hif_usb: fix race condition between usb_get_urb() and usb_kill_anchored_urbs() misc: rtsx: Fix memory leak in rtsx_pci_probe reiserfs: only call unlock_new_inode() if I_NEW xfs: make sure the rt allocator doesn't run off the end usb: ohci: Default to per-port over-current protection Bluetooth: Only mark socket zapped after unlocking scsi: ibmvfc: Fix error return in ibmvfc_probe() brcmsmac: fix memory leak in wlc_phy_attach_lcnphy rtl8xxxu: prevent potential memory leak Fix use after free in get_capset_info callback. tty: ipwireless: fix error handling ipvs: Fix uninit-value in do_ip_vs_set_ctl() reiserfs: Fix memory leak in reiserfs_parse_options() brcm80211: fix possible memleak in brcmf_proto_msgbuf_attach usb: core: Solve race condition in anchor cleanup functions ath10k: check idx validity in __ath10k_htt_rx_ring_fill_n() net: korina: cast KSEG0 address to pointer in kfree usb: cdc-acm: add quirk to blacklist ETAS ES58X devices USB: cdc-wdm: Make wdm_flush() interruptible and add wdm_fsync(). Linux 4.4.241 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I996be1c1248d000431eb6f5c53472dbafba8bd9c
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/class/cdc-acm.c11
-rw-r--r--drivers/usb/class/cdc-wdm.c72
-rw-r--r--drivers/usb/core/urb.c89
-rw-r--r--drivers/usb/gadget/function/f_printer.c16
-rw-r--r--drivers/usb/gadget/function/u_ether.c2
-rw-r--r--drivers/usb/host/ohci-hcd.c16
6 files changed, 145 insertions, 61 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 515839034dfb..fb7e56fad41c 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1897,6 +1897,17 @@ static const struct usb_device_id acm_ids[] = {
.driver_info = IGNORE_DEVICE,
},
+ /* Exclude ETAS ES58x */
+ { USB_DEVICE(0x108c, 0x0159), /* ES581.4 */
+ .driver_info = IGNORE_DEVICE,
+ },
+ { USB_DEVICE(0x108c, 0x0168), /* ES582.1 */
+ .driver_info = IGNORE_DEVICE,
+ },
+ { USB_DEVICE(0x108c, 0x0169), /* ES584.1 */
+ .driver_info = IGNORE_DEVICE,
+ },
+
{ USB_DEVICE(0x1bc7, 0x0021), /* Telit 3G ACM only composition */
.driver_info = SEND_ZERO_PACKET,
},
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 1a1d1cfc3704..35ee2233ad17 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -61,6 +61,9 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_MAX 16
+/* we cannot wait forever at flush() */
+#define WDM_FLUSH_TIMEOUT (30 * HZ)
+
/* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)" */
#define WDM_DEFAULT_BUFSIZE 256
@@ -151,7 +154,7 @@ static void wdm_out_callback(struct urb *urb)
kfree(desc->outbuf);
desc->outbuf = NULL;
clear_bit(WDM_IN_USE, &desc->flags);
- wake_up(&desc->wait);
+ wake_up_all(&desc->wait);
}
static void wdm_in_callback(struct urb *urb)
@@ -382,6 +385,9 @@ static ssize_t wdm_write
if (test_bit(WDM_RESETTING, &desc->flags))
r = -EIO;
+ if (test_bit(WDM_DISCONNECTING, &desc->flags))
+ r = -ENODEV;
+
if (r < 0) {
rv = r;
goto out_free_mem_pm;
@@ -413,6 +419,7 @@ static ssize_t wdm_write
if (rv < 0) {
desc->outbuf = NULL;
clear_bit(WDM_IN_USE, &desc->flags);
+ wake_up_all(&desc->wait); /* for wdm_wait_for_response() */
dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv);
rv = usb_translate_errors(rv);
goto out_free_mem_pm;
@@ -573,28 +580,58 @@ err:
return rv;
}
-static int wdm_flush(struct file *file, fl_owner_t id)
+static int wdm_wait_for_response(struct file *file, long timeout)
{
struct wdm_device *desc = file->private_data;
+ long rv; /* Use long here because (int) MAX_SCHEDULE_TIMEOUT < 0. */
- wait_event(desc->wait,
- /*
- * needs both flags. We cannot do with one
- * because resetting it would cause a race
- * with write() yet we need to signal
- * a disconnect
- */
- !test_bit(WDM_IN_USE, &desc->flags) ||
- test_bit(WDM_DISCONNECTING, &desc->flags));
-
- /* cannot dereference desc->intf if WDM_DISCONNECTING */
+ /*
+ * Needs both flags. We cannot do with one because resetting it would
+ * cause a race with write() yet we need to signal a disconnect.
+ */
+ rv = wait_event_interruptible_timeout(desc->wait,
+ !test_bit(WDM_IN_USE, &desc->flags) ||
+ test_bit(WDM_DISCONNECTING, &desc->flags),
+ timeout);
+
+ /*
+ * To report the correct error. This is best effort.
+ * We are inevitably racing with the hardware.
+ */
if (test_bit(WDM_DISCONNECTING, &desc->flags))
return -ENODEV;
- if (desc->werr < 0)
- dev_err(&desc->intf->dev, "Error in flush path: %d\n",
- desc->werr);
+ if (!rv)
+ return -EIO;
+ if (rv < 0)
+ return -EINTR;
- return usb_translate_errors(desc->werr);
+ spin_lock_irq(&desc->iuspin);
+ rv = desc->werr;
+ desc->werr = 0;
+ spin_unlock_irq(&desc->iuspin);
+
+ return usb_translate_errors(rv);
+
+}
+
+/*
+ * You need to send a signal when you react to malicious or defective hardware.
+ * Also, don't abort when fsync() returned -EINVAL, for older kernels which do
+ * not implement wdm_flush() will return -EINVAL.
+ */
+static int wdm_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+ return wdm_wait_for_response(file, MAX_SCHEDULE_TIMEOUT);
+}
+
+/*
+ * Same with wdm_fsync(), except it uses finite timeout in order to react to
+ * malicious or defective hardware which ceased communication after close() was
+ * implicitly called due to process termination.
+ */
+static int wdm_flush(struct file *file, fl_owner_t id)
+{
+ return wdm_wait_for_response(file, WDM_FLUSH_TIMEOUT);
}
static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait)
@@ -719,6 +756,7 @@ static const struct file_operations wdm_fops = {
.owner = THIS_MODULE,
.read = wdm_read,
.write = wdm_write,
+ .fsync = wdm_fsync,
.open = wdm_open,
.flush = wdm_flush,
.release = wdm_release,
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index c095cde55329..8c4bfd42f785 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -767,11 +767,12 @@ void usb_block_urb(struct urb *urb)
EXPORT_SYMBOL_GPL(usb_block_urb);
/**
- * usb_kill_anchored_urbs - cancel transfer requests en masse
+ * usb_kill_anchored_urbs - kill all URBs associated with an anchor
* @anchor: anchor the requests are bound to
*
- * this allows all outstanding URBs to be killed starting
- * from the back of the queue
+ * This kills all outstanding URBs starting from the back of the queue,
+ * with guarantee that no completer callbacks will take place from the
+ * anchor after this function returns.
*
* This routine should not be called by a driver after its disconnect
* method has returned.
@@ -779,20 +780,26 @@ EXPORT_SYMBOL_GPL(usb_block_urb);
void usb_kill_anchored_urbs(struct usb_anchor *anchor)
{
struct urb *victim;
+ int surely_empty;
- spin_lock_irq(&anchor->lock);
- while (!list_empty(&anchor->urb_list)) {
- victim = list_entry(anchor->urb_list.prev, struct urb,
- anchor_list);
- /* we must make sure the URB isn't freed before we kill it*/
- usb_get_urb(victim);
- spin_unlock_irq(&anchor->lock);
- /* this will unanchor the URB */
- usb_kill_urb(victim);
- usb_put_urb(victim);
+ do {
spin_lock_irq(&anchor->lock);
- }
- spin_unlock_irq(&anchor->lock);
+ while (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.prev,
+ struct urb, anchor_list);
+ /* make sure the URB isn't freed before we kill it */
+ usb_get_urb(victim);
+ spin_unlock_irq(&anchor->lock);
+ /* this will unanchor the URB */
+ usb_kill_urb(victim);
+ usb_put_urb(victim);
+ spin_lock_irq(&anchor->lock);
+ }
+ surely_empty = usb_anchor_check_wakeup(anchor);
+
+ spin_unlock_irq(&anchor->lock);
+ cpu_relax();
+ } while (!surely_empty);
}
EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs);
@@ -811,21 +818,27 @@ EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs);
void usb_poison_anchored_urbs(struct usb_anchor *anchor)
{
struct urb *victim;
+ int surely_empty;
- spin_lock_irq(&anchor->lock);
- anchor->poisoned = 1;
- while (!list_empty(&anchor->urb_list)) {
- victim = list_entry(anchor->urb_list.prev, struct urb,
- anchor_list);
- /* we must make sure the URB isn't freed before we kill it*/
- usb_get_urb(victim);
- spin_unlock_irq(&anchor->lock);
- /* this will unanchor the URB */
- usb_poison_urb(victim);
- usb_put_urb(victim);
+ do {
spin_lock_irq(&anchor->lock);
- }
- spin_unlock_irq(&anchor->lock);
+ anchor->poisoned = 1;
+ while (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.prev,
+ struct urb, anchor_list);
+ /* make sure the URB isn't freed before we kill it */
+ usb_get_urb(victim);
+ spin_unlock_irq(&anchor->lock);
+ /* this will unanchor the URB */
+ usb_poison_urb(victim);
+ usb_put_urb(victim);
+ spin_lock_irq(&anchor->lock);
+ }
+ surely_empty = usb_anchor_check_wakeup(anchor);
+
+ spin_unlock_irq(&anchor->lock);
+ cpu_relax();
+ } while (!surely_empty);
}
EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs);
@@ -965,14 +978,20 @@ void usb_scuttle_anchored_urbs(struct usb_anchor *anchor)
{
struct urb *victim;
unsigned long flags;
+ int surely_empty;
+
+ do {
+ spin_lock_irqsave(&anchor->lock, flags);
+ while (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.prev,
+ struct urb, anchor_list);
+ __usb_unanchor_urb(victim, anchor);
+ }
+ surely_empty = usb_anchor_check_wakeup(anchor);
- spin_lock_irqsave(&anchor->lock, flags);
- while (!list_empty(&anchor->urb_list)) {
- victim = list_entry(anchor->urb_list.prev, struct urb,
- anchor_list);
- __usb_unanchor_urb(victim, anchor);
- }
- spin_unlock_irqrestore(&anchor->lock, flags);
+ spin_unlock_irqrestore(&anchor->lock, flags);
+ cpu_relax();
+ } while (!surely_empty);
}
EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs);
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index 69afc17fca38..7b21ef09fffc 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -35,6 +35,7 @@
#include <linux/types.h>
#include <linux/ctype.h>
#include <linux/cdev.h>
+#include <linux/kref.h>
#include <asm/byteorder.h>
#include <linux/io.h>
@@ -69,7 +70,7 @@ struct printer_dev {
struct usb_gadget *gadget;
s8 interface;
struct usb_ep *in_ep, *out_ep;
-
+ struct kref kref;
struct list_head rx_reqs; /* List of free RX structs */
struct list_head rx_reqs_active; /* List of Active RX xfers */
struct list_head rx_buffers; /* List of completed xfers */
@@ -223,6 +224,13 @@ static inline struct usb_endpoint_descriptor *ep_desc(struct usb_gadget *gadget,
/*-------------------------------------------------------------------------*/
+static void printer_dev_free(struct kref *kref)
+{
+ struct printer_dev *dev = container_of(kref, struct printer_dev, kref);
+
+ kfree(dev);
+}
+
static struct usb_request *
printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags)
{
@@ -353,6 +361,7 @@ printer_open(struct inode *inode, struct file *fd)
spin_unlock_irqrestore(&dev->lock, flags);
+ kref_get(&dev->kref);
DBG(dev, "printer_open returned %x\n", ret);
return ret;
}
@@ -370,6 +379,7 @@ printer_close(struct inode *inode, struct file *fd)
dev->printer_status &= ~PRINTER_SELECTED;
spin_unlock_irqrestore(&dev->lock, flags);
+ kref_put(&dev->kref, printer_dev_free);
DBG(dev, "printer_close\n");
return 0;
@@ -1316,7 +1326,8 @@ static void gprinter_free(struct usb_function *f)
struct f_printer_opts *opts;
opts = container_of(f->fi, struct f_printer_opts, func_inst);
- kfree(dev);
+
+ kref_put(&dev->kref, printer_dev_free);
mutex_lock(&opts->lock);
--opts->refcnt;
mutex_unlock(&opts->lock);
@@ -1385,6 +1396,7 @@ static struct usb_function *gprinter_alloc(struct usb_function_instance *fi)
return ERR_PTR(-ENOMEM);
}
+ kref_init(&dev->kref);
++opts->refcnt;
dev->minor = opts->minor;
dev->pnp_string = opts->pnp_string;
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 0d6106e9d51b..0a0eeffc9438 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -106,7 +106,7 @@ struct eth_dev {
static inline int qlen(struct usb_gadget *gadget, unsigned qmult)
{
if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH ||
- gadget->speed == USB_SPEED_SUPER))
+ gadget->speed >= USB_SPEED_SUPER))
return qmult * DEFAULT_QLEN;
else
return DEFAULT_QLEN;
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 27bd3e49fe8e..07d76d9d4ce1 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -663,20 +663,24 @@ retry:
/* handle root hub init quirks ... */
val = roothub_a (ohci);
- val &= ~(RH_A_PSM | RH_A_OCPM);
+ /* Configure for per-port over-current protection by default */
+ val &= ~RH_A_NOCP;
+ val |= RH_A_OCPM;
if (ohci->flags & OHCI_QUIRK_SUPERIO) {
- /* NSC 87560 and maybe others */
+ /* NSC 87560 and maybe others.
+ * Ganged power switching, no over-current protection.
+ */
val |= RH_A_NOCP;
- val &= ~(RH_A_POTPGT | RH_A_NPS);
- ohci_writel (ohci, val, &ohci->regs->roothub.a);
+ val &= ~(RH_A_POTPGT | RH_A_NPS | RH_A_PSM | RH_A_OCPM);
} else if ((ohci->flags & OHCI_QUIRK_AMD756) ||
(ohci->flags & OHCI_QUIRK_HUB_POWER)) {
/* hub power always on; required for AMD-756 and some
- * Mac platforms. ganged overcurrent reporting, if any.
+ * Mac platforms.
*/
val |= RH_A_NPS;
- ohci_writel (ohci, val, &ohci->regs->roothub.a);
}
+ ohci_writel(ohci, val, &ohci->regs->roothub.a);
+
ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status);
ohci_writel (ohci, (val & RH_A_NPS) ? 0 : RH_B_PPCM,
&ohci->regs->roothub.b);