| From 3c6f8cb92c9178fc0c66b580ea3df1fa3ac1155a Mon Sep 17 00:00:00 2001 |
| From: Sriharsha Allenki <sallenki@codeaurora.org> |
| Date: Thu, 14 May 2020 14:04:31 +0300 |
| Subject: usb: xhci: Fix NULL pointer dereference when enqueuing trbs from urb sg list |
| |
| From: Sriharsha Allenki <sallenki@codeaurora.org> |
| |
| commit 3c6f8cb92c9178fc0c66b580ea3df1fa3ac1155a upstream. |
| |
| On platforms with IOMMU enabled, multiple SGs can be coalesced into one |
| by the IOMMU driver. In that case the SG list processing as part of the |
| completion of a urb on a bulk endpoint can result into a NULL pointer |
| dereference with the below stack dump. |
| |
| <6> Unable to handle kernel NULL pointer dereference at virtual address 0000000c |
| <6> pgd = c0004000 |
| <6> [0000000c] *pgd=00000000 |
| <6> Internal error: Oops: 5 [#1] PREEMPT SMP ARM |
| <2> PC is at xhci_queue_bulk_tx+0x454/0x80c |
| <2> LR is at xhci_queue_bulk_tx+0x44c/0x80c |
| <2> pc : [<c08907c4>] lr : [<c08907bc>] psr: 000000d3 |
| <2> sp : ca337c80 ip : 00000000 fp : ffffffff |
| <2> r10: 00000000 r9 : 50037000 r8 : 00004000 |
| <2> r7 : 00000000 r6 : 00004000 r5 : 00000000 r4 : 00000000 |
| <2> r3 : 00000000 r2 : 00000082 r1 : c2c1a200 r0 : 00000000 |
| <2> Flags: nzcv IRQs off FIQs off Mode SVC_32 ISA ARM Segment none |
| <2> Control: 10c0383d Table: b412c06a DAC: 00000051 |
| <6> Process usb-storage (pid: 5961, stack limit = 0xca336210) |
| <snip> |
| <2> [<c08907c4>] (xhci_queue_bulk_tx) |
| <2> [<c0881b3c>] (xhci_urb_enqueue) |
| <2> [<c0831068>] (usb_hcd_submit_urb) |
| <2> [<c08350b4>] (usb_sg_wait) |
| <2> [<c089f384>] (usb_stor_bulk_transfer_sglist) |
| <2> [<c089f2c0>] (usb_stor_bulk_srb) |
| <2> [<c089fe38>] (usb_stor_Bulk_transport) |
| <2> [<c089f468>] (usb_stor_invoke_transport) |
| <2> [<c08a11b4>] (usb_stor_control_thread) |
| <2> [<c014a534>] (kthread) |
| |
| The above NULL pointer dereference is the result of block_len and the |
| sent_len set to zero after the first SG of the list when IOMMU driver |
| is enabled. Because of this the loop of processing the SGs has run |
| more than num_sgs which resulted in a sg_next on the last SG of the |
| list which has SG_END set. |
| |
| Fix this by check for the sg before any attributes of the sg are |
| accessed. |
| |
| [modified reason for null pointer dereference in commit message subject -Mathias] |
| Fixes: f9c589e142d04 ("xhci: TD-fragment, align the unsplittable case with a bounce buffer") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Sriharsha Allenki <sallenki@codeaurora.org> |
| Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> |
| Link: https://lore.kernel.org/r/20200514110432.25564-2-mathias.nyman@linux.intel.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/host/xhci-ring.c | 4 ++-- |
| 1 file changed, 2 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/usb/host/xhci-ring.c |
| +++ b/drivers/usb/host/xhci-ring.c |
| @@ -3425,8 +3425,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd * |
| /* New sg entry */ |
| --num_sgs; |
| sent_len -= block_len; |
| - if (num_sgs != 0) { |
| - sg = sg_next(sg); |
| + sg = sg_next(sg); |
| + if (num_sgs != 0 && sg) { |
| block_len = sg_dma_len(sg); |
| addr = (u64) sg_dma_address(sg); |
| addr += sent_len; |