| From 409ecdf5cc5bad88a79b341435511c760501ba65 Mon Sep 17 00:00:00 2001 |
| From: Lu Baolu <baolu.lu@linux.intel.com> |
| Date: Tue, 3 Jan 2017 18:28:46 +0200 |
| Subject: [PATCH] usb: xhci: fix possible wild pointer |
| |
| commit 2b985467371a58ae44d76c7ba12b0951fee6ed98 upstream. |
| |
| handle_cmd_completion() frees a command structure which might be still |
| referenced by xhci->current_cmd. |
| This might cause problem when xhci->current_cmd is accessed after that. |
| |
| A real-life case could be like this. The host takes a very long time to |
| respond to a command, and the command timer is fired at the same time |
| when the command completion event arrives. The command completion |
| handler frees xhci->current_cmd before the timer function can grab |
| xhci->lock. Afterward, timer function grabs the lock and go ahead with |
| checking and setting members of xhci->current_cmd. |
| |
| Cc: <stable@vger.kernel.org> # v3.16+ |
| Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> |
| Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c |
| index 797137e26549..f7431f4df5a3 100644 |
| --- a/drivers/usb/host/xhci-ring.c |
| +++ b/drivers/usb/host/xhci-ring.c |
| @@ -1271,14 +1271,18 @@ void xhci_handle_command_timeout(unsigned long data) |
| bool second_timeout = false; |
| xhci = (struct xhci_hcd *) data; |
| |
| - /* mark this command to be cancelled */ |
| spin_lock_irqsave(&xhci->lock, flags); |
| - if (xhci->current_cmd) { |
| - if (xhci->current_cmd->status == COMP_CMD_ABORT) |
| - second_timeout = true; |
| - xhci->current_cmd->status = COMP_CMD_ABORT; |
| + |
| + if (!xhci->current_cmd) { |
| + spin_unlock_irqrestore(&xhci->lock, flags); |
| + return; |
| } |
| |
| + /* mark this command to be cancelled */ |
| + if (xhci->current_cmd->status == COMP_CMD_ABORT) |
| + second_timeout = true; |
| + xhci->current_cmd->status = COMP_CMD_ABORT; |
| + |
| /* Make sure command ring is running before aborting it */ |
| hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); |
| if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) && |
| @@ -1427,6 +1431,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, |
| xhci->current_cmd = list_entry(cmd->cmd_list.next, |
| struct xhci_command, cmd_list); |
| mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT); |
| + } else if (xhci->current_cmd == cmd) { |
| + xhci->current_cmd = NULL; |
| } |
| |
| event_handled: |
| -- |
| 2.10.1 |
| |