Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753609AbdGYTyx (ORCPT ); Tue, 25 Jul 2017 15:54:53 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:36054 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753730AbdGYTY0 (ORCPT ); Tue, 25 Jul 2017 15:24:26 -0400 From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, rocko r , Mathias Nyman Subject: [PATCH 4.12 067/196] xhci: Fix NULL pointer dereference when cleaning up streams for removed host Date: Tue, 25 Jul 2017 12:21:06 -0700 Message-Id: <20170725192049.934677831@linuxfoundation.org> X-Mailer: git-send-email 2.13.3 In-Reply-To: <20170725192046.422343510@linuxfoundation.org> References: <20170725192046.422343510@linuxfoundation.org> User-Agent: quilt/0.65 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 1751 Lines: 51 4.12-stable review patch. If anyone has any objections, please let me know. ------------------ From: Mathias Nyman commit 4b895868bb2da60a386a17cde3bf9ecbc70c79f4 upstream. This off by one in stream_id indexing caused NULL pointer dereference and soft lockup on machines with USB attached SCSI devices connected to a hotpluggable xhci controller. The code that cleans up pending URBs for dead hosts tried to dereference a stream ring at the invalid stream_id 0. ep->stream_info->stream_rings[0] doesn't point to a ring. Start looping stream_id from 1 like in all the other places in the driver, and check that the ring exists before trying to kill URBs on it. Reported-by: rocko r Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -845,13 +845,16 @@ static void xhci_kill_endpoint_urbs(stru (ep->ep_state & EP_GETTING_NO_STREAMS)) { int stream_id; - for (stream_id = 0; stream_id < ep->stream_info->num_streams; + for (stream_id = 1; stream_id < ep->stream_info->num_streams; stream_id++) { + ring = ep->stream_info->stream_rings[stream_id]; + if (!ring) + continue; + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Killing URBs for slot ID %u, ep index %u, stream %u", - slot_id, ep_index, stream_id + 1); - xhci_kill_ring_urbs(xhci, - ep->stream_info->stream_rings[stream_id]); + slot_id, ep_index, stream_id); + xhci_kill_ring_urbs(xhci, ring); } } else { ring = ep->ring;