Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 310fa201 authored by Jonathan Bell's avatar Jonathan Bell Committed by Greg Kroah-Hartman
Browse files

xhci: guard accesses to ep_state in xhci_endpoint_reset()

commit a01ba2a3378be85538e0183ae5367c1bc1d5aaf3 upstream.

See https://github.com/raspberrypi/linux/issues/3981



Two read-modify-write cycles on ep->ep_state are not guarded by
xhci->lock. Fix these.

Fixes: f5249461 ("xhci: Clear the host side toggle manually when endpoint is soft reset")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarJonathan Bell <jonathan@raspberrypi.com>
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20211008092547.3996295-2-mathias.nyman@linux.intel.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f67443c5
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -3093,10 +3093,13 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
	ep = &vdev->eps[ep_index];
	ep = &vdev->eps[ep_index];


	/* Bail out if toggle is already being cleared by a endpoint reset */
	/* Bail out if toggle is already being cleared by a endpoint reset */
	spin_lock_irqsave(&xhci->lock, flags);
	if (ep->ep_state & EP_HARD_CLEAR_TOGGLE) {
	if (ep->ep_state & EP_HARD_CLEAR_TOGGLE) {
		ep->ep_state &= ~EP_HARD_CLEAR_TOGGLE;
		ep->ep_state &= ~EP_HARD_CLEAR_TOGGLE;
		spin_unlock_irqrestore(&xhci->lock, flags);
		return;
		return;
	}
	}
	spin_unlock_irqrestore(&xhci->lock, flags);
	/* Only interrupt and bulk ep's use data toggle, USB2 spec 5.5.4-> */
	/* Only interrupt and bulk ep's use data toggle, USB2 spec 5.5.4-> */
	if (usb_endpoint_xfer_control(&host_ep->desc) ||
	if (usb_endpoint_xfer_control(&host_ep->desc) ||
	    usb_endpoint_xfer_isoc(&host_ep->desc))
	    usb_endpoint_xfer_isoc(&host_ep->desc))
@@ -3182,8 +3185,10 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
	xhci_free_command(xhci, cfg_cmd);
	xhci_free_command(xhci, cfg_cmd);
cleanup:
cleanup:
	xhci_free_command(xhci, stop_cmd);
	xhci_free_command(xhci, stop_cmd);
	spin_lock_irqsave(&xhci->lock, flags);
	if (ep->ep_state & EP_SOFT_CLEAR_TOGGLE)
	if (ep->ep_state & EP_SOFT_CLEAR_TOGGLE)
		ep->ep_state &= ~EP_SOFT_CLEAR_TOGGLE;
		ep->ep_state &= ~EP_SOFT_CLEAR_TOGGLE;
	spin_unlock_irqrestore(&xhci->lock, flags);
}
}


static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,
static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,