From: Mathias Nyman mathias.nyman@linux.intel.com
mainline inclusion from mainline-v5.2-rc3 commit 13b82b746310b51b064bc855993a1c84bf862726 bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9DNQ5 CVE: CVE-2024-26659
--------------------------------
xhci immediate data transfer (IDT) support in 5.2-rc1 caused regression on various Samsung Exynos boards with ASIX USB 2.0 ethernet dongle.
If the transfer buffer in the URB is already DMA mapped then IDT should not be used. urb->transfer_dma will already contain a valid dma address, and there is no guarantee the data in urb->transfer_buffer is valid.
The IDT support patch used urb->transfer_dma as a temporary storage, copying data from urb->transfer_buffer into it.
Issue was solved by preventing IDT if transfer buffer is already dma mapped, and by not using urb->transfer_dma as temporary storage.
Fixes: 33e39350ebd2 ("usb: xhci: add Immediate Data Transfer support") Reported-by: Marek Szyprowski m.szyprowski@samsung.com Tested-by: Marek Szyprowski m.szyprowski@samsung.com CC: Nicolas Saenz Julienne nsaenzjulienne@suse.de Signed-off-by: Mathias Nyman mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Li Huafei lihuafei1@huawei.com --- drivers/usb/host/xhci-ring.c | 9 ++++++--- drivers/usb/host/xhci.h | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 959f781c7160..d4fd26df3b54 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3441,11 +3441,14 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
if (urb->transfer_buffer_length > 0) { u32 length_field, remainder; + u64 addr;
if (xhci_urb_suitable_for_idt(urb)) { - memcpy(&urb->transfer_dma, urb->transfer_buffer, + memcpy(&addr, urb->transfer_buffer, urb->transfer_buffer_length); field |= TRB_IDT; + } else { + addr = (u64) urb->transfer_dma; }
remainder = xhci_td_remainder(xhci, 0, @@ -3458,8 +3461,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (setup->bRequestType & USB_DIR_IN) field |= TRB_DIR_IN; queue_trb(xhci, ep_ring, true, - lower_32_bits(urb->transfer_dma), - upper_32_bits(urb->transfer_dma), + lower_32_bits(addr), + upper_32_bits(addr), length_field, field | ep_ring->cycle_state); } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 17c4687df3de..817dad16a32d 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2190,7 +2190,8 @@ static inline bool xhci_urb_suitable_for_idt(struct urb *urb) { if (!usb_endpoint_xfer_isoc(&urb->ep->desc) && usb_urb_dir_out(urb) && usb_endpoint_maxp(&urb->ep->desc) >= TRB_IDT_MAX_SIZE && - urb->transfer_buffer_length <= TRB_IDT_MAX_SIZE) + urb->transfer_buffer_length <= TRB_IDT_MAX_SIZE && + !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) return true;
return false;