aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host/xhci.c
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2018-10-01 12:15:41 +0100
committerMark Brown <broonie@kernel.org>2018-10-01 12:15:41 +0100
commit5410a50744229bec3b4a182ff1d6e847957014c2 (patch)
treec2e1f0042238961ec43a2ca88d6d366dc80436f1 /drivers/usb/host/xhci.c
parentd7b33ebae7c1419ebdfd94eb64bf74a7ec760031 (diff)
parent3b65f403d7d0e98484e8f2c9471808f2785a8235 (diff)
Merge tag 'v4.14.73' into linux-linaro-lsk-v4.14lsk-v4.14-18.09
This is the 4.14.73 stable release # gpg: Signature made Sat 29 Sep 2018 11:06:11 BST # gpg: using RSA key 647F28654894E3BD457199BE38DBBDC86092693E # gpg: Good signature from "Greg Kroah-Hartman <gregkh@linuxfoundation.org>" [unknown] # gpg: aka "Greg Kroah-Hartman (Linux kernel stable release signing key) <greg@kroah.com>" [unknown] # gpg: aka "Greg Kroah-Hartman <gregkh@kernel.org>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 647F 2865 4894 E3BD 4571 99BE 38DB BDC8 6092 693E
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r--drivers/usb/host/xhci.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 6b11fd9d8efe..64ddba3f79a9 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -47,6 +47,21 @@ static unsigned int quirks;
module_param(quirks, uint, S_IRUGO);
MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default");
+static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring)
+{
+ struct xhci_segment *seg = ring->first_seg;
+
+ if (!td || !td->start_seg)
+ return false;
+ do {
+ if (seg == td->start_seg)
+ return true;
+ seg = seg->next;
+ } while (seg && seg != ring->first_seg);
+
+ return false;
+}
+
/* TODO: copied from ehci-hcd.c - can this be refactored? */
/*
* xhci_handshake - spin reading hc until handshake completes or fails
@@ -1511,6 +1526,21 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
goto done;
}
+ /*
+ * check ring is not re-allocated since URB was enqueued. If it is, then
+ * make sure none of the ring related pointers in this URB private data
+ * are touched, such as td_list, otherwise we overwrite freed data
+ */
+ if (!td_on_ring(&urb_priv->td[0], ep_ring)) {
+ xhci_err(xhci, "Canceled URB td not found on endpoint ring");
+ for (i = urb_priv->num_tds_done; i < urb_priv->num_tds; i++) {
+ td = &urb_priv->td[i];
+ if (!list_empty(&td->cancelled_td_list))
+ list_del_init(&td->cancelled_td_list);
+ }
+ goto err_giveback;
+ }
+
if (xhci->xhc_state & XHCI_STATE_HALTED) {
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
"HC halted, freeing TD manually.");