Received: by 2002:a05:6a10:1287:0:0:0:0 with SMTP id d7csp3718507pxv; Mon, 26 Jul 2021 10:09:29 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzngPXrt2WT2vQamLO8kk6t2AKDPWJJByNpb8T7Hi3xQ/B/yPDvLmCmIpLSgmc3EDKtYKka X-Received: by 2002:a17:906:7951:: with SMTP id l17mr18167496ejo.529.1627319369229; Mon, 26 Jul 2021 10:09:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1627319369; cv=none; d=google.com; s=arc-20160816; b=CoT2Xlcqzl1PRC+zP6rQAEuO5oVbtdLf1ToLZfudeT6eLKn5878zaA+Jfu0v6dGOJ3 PWz0aOvgB07ZmOZehzrkmtFcyIaeYfKcC5MDDh5RTpWF0F+8flIoy7jeN33sPGdxuWAB iGWHxfA1pLI7EgatSRqS8N7vIcRwO7aDEbCKxQKclV0HX6PJjflx3A2rZ5JIjuP62q+7 xHgocHCg4c70npbrFjFqBzwJJX9Zo7WvxP816cftEeZUr32JKuFT4EOdjoaZtybTKrkG hYS8UNLuixys3x7itJ70Lwtc9bh7PdYAdkwWkEC8AJrC+3Fz6BEyaqigk8UhoKPnp/My n5AQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=BR3OwMJeZWw6exOo+sEDq9WWnMvxM+FKs9Lsj6Lsq5Y=; b=yAPfIF4tAU8+wG5gDIYCbL5Wih4vqzyCZD2TmCQD/qHRNo+h3kKPvzdtcYh1pxRwZC bzHhSw7FKnOPADNcQ0VjQVhLJq0NITLupZCfzq7WiYkrU/0EDTDXQjF7GFj/9F54YTQC BkLpBC/fTO3QR+PPgZF1KZiWHMl6K6ZqCrXc0kFWMpTTuaUIk/m1Rwofp/eGRYSbiYoc kpkmhIbAZmnmvzTFh3qNTj9abTR1pDhOsANTNd0+o/EI1YPZN0AdZoXsf2MBZBePso5Q /2aSwSSUNb7Q47DzVMUbndQv7jXqgwIVhlTYOD193rN31BneOOlY96emjmsR3Yen2NGn kEpA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=xNvBFVRz; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id m22si459867edb.588.2021.07.26.10.09.06; Mon, 26 Jul 2021 10:09:29 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=xNvBFVRz; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238557AbhGZPnc (ORCPT + 99 others); Mon, 26 Jul 2021 11:43:32 -0400 Received: from mail.kernel.org ([198.145.29.99]:39898 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238067AbhGZPYh (ORCPT ); Mon, 26 Jul 2021 11:24:37 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id BBD7E60E09; Mon, 26 Jul 2021 16:05:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1627315505; bh=Z8xvYOwArq6z6cOpGIaDz6plqC40jynkMy5CihLFma8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=xNvBFVRz0/oP2H5dhQ5nFkhyB/PvPjMmbdARbyywm77jvfisOtDzL08wFv5aV8R/F 7bYDK4WtZKY0kiYY6CEf8BCnAAkDQnlBh0rzu70eeF6d22d1b7oRYW6rNeabPaMP72 dtpTv1dU0siCMmaAzoJdoTZm4ZQWgI7Rjil8f7q0= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Mark Tomlinson Subject: [PATCH 5.10 124/167] usb: max-3421: Prevent corruption of freed memory Date: Mon, 26 Jul 2021 17:39:17 +0200 Message-Id: <20210726153843.564988264@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210726153839.371771838@linuxfoundation.org> References: <20210726153839.371771838@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Mark Tomlinson commit b5fdf5c6e6bee35837e160c00ac89327bdad031b upstream. The MAX-3421 USB driver remembers the state of the USB toggles for a device/endpoint. To save SPI writes, this was only done when a new device/endpoint was being used. Unfortunately, if the old device was removed, this would cause writes to freed memory. To fix this, a simpler scheme is used. The toggles are read from hardware when a URB is completed, and the toggles are always written to hardware when any URB transaction is started. This will cause a few more SPI transactions, but no causes kernel panics. Fixes: 2d53139f3162 ("Add support for using a MAX3421E chip as a host driver.") Cc: stable Signed-off-by: Mark Tomlinson Link: https://lore.kernel.org/r/20210625031456.8632-1-mark.tomlinson@alliedtelesis.co.nz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/max3421-hcd.c | 44 +++++++++++++---------------------------- 1 file changed, 14 insertions(+), 30 deletions(-) --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -153,8 +153,6 @@ struct max3421_hcd { */ struct urb *curr_urb; enum scheduling_pass sched_pass; - struct usb_device *loaded_dev; /* dev that's loaded into the chip */ - int loaded_epnum; /* epnum whose toggles are loaded */ int urb_done; /* > 0 -> no errors, < 0: errno */ size_t curr_len; u8 hien; @@ -492,39 +490,17 @@ max3421_set_speed(struct usb_hcd *hcd, s * Caller must NOT hold HCD spinlock. */ static void -max3421_set_address(struct usb_hcd *hcd, struct usb_device *dev, int epnum, - int force_toggles) +max3421_set_address(struct usb_hcd *hcd, struct usb_device *dev, int epnum) { - struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); - int old_epnum, same_ep, rcvtog, sndtog; - struct usb_device *old_dev; + int rcvtog, sndtog; u8 hctl; - old_dev = max3421_hcd->loaded_dev; - old_epnum = max3421_hcd->loaded_epnum; - - same_ep = (dev == old_dev && epnum == old_epnum); - if (same_ep && !force_toggles) - return; - - if (old_dev && !same_ep) { - /* save the old end-points toggles: */ - u8 hrsl = spi_rd8(hcd, MAX3421_REG_HRSL); - - rcvtog = (hrsl >> MAX3421_HRSL_RCVTOGRD_BIT) & 1; - sndtog = (hrsl >> MAX3421_HRSL_SNDTOGRD_BIT) & 1; - - /* no locking: HCD (i.e., we) own toggles, don't we? */ - usb_settoggle(old_dev, old_epnum, 0, rcvtog); - usb_settoggle(old_dev, old_epnum, 1, sndtog); - } /* setup new endpoint's toggle bits: */ rcvtog = usb_gettoggle(dev, epnum, 0); sndtog = usb_gettoggle(dev, epnum, 1); hctl = (BIT(rcvtog + MAX3421_HCTL_RCVTOG0_BIT) | BIT(sndtog + MAX3421_HCTL_SNDTOG0_BIT)); - max3421_hcd->loaded_epnum = epnum; spi_wr8(hcd, MAX3421_REG_HCTL, hctl); /* @@ -532,7 +508,6 @@ max3421_set_address(struct usb_hcd *hcd, * address-assignment so it's best to just always load the * address whenever the end-point changed/was forced. */ - max3421_hcd->loaded_dev = dev; spi_wr8(hcd, MAX3421_REG_PERADDR, dev->devnum); } @@ -667,7 +642,7 @@ max3421_select_and_start_urb(struct usb_ struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); struct urb *urb, *curr_urb = NULL; struct max3421_ep *max3421_ep; - int epnum, force_toggles = 0; + int epnum; struct usb_host_endpoint *ep; struct list_head *pos; unsigned long flags; @@ -777,7 +752,6 @@ done: usb_settoggle(urb->dev, epnum, 0, 1); usb_settoggle(urb->dev, epnum, 1, 1); max3421_ep->pkt_state = PKT_STATE_SETUP; - force_toggles = 1; } else max3421_ep->pkt_state = PKT_STATE_TRANSFER; } @@ -785,7 +759,7 @@ done: spin_unlock_irqrestore(&max3421_hcd->lock, flags); max3421_ep->last_active = max3421_hcd->frame_number; - max3421_set_address(hcd, urb->dev, epnum, force_toggles); + max3421_set_address(hcd, urb->dev, epnum); max3421_set_speed(hcd, urb->dev); max3421_next_transfer(hcd, 0); return 1; @@ -1380,6 +1354,16 @@ max3421_urb_done(struct usb_hcd *hcd) status = 0; urb = max3421_hcd->curr_urb; if (urb) { + /* save the old end-points toggles: */ + u8 hrsl = spi_rd8(hcd, MAX3421_REG_HRSL); + int rcvtog = (hrsl >> MAX3421_HRSL_RCVTOGRD_BIT) & 1; + int sndtog = (hrsl >> MAX3421_HRSL_SNDTOGRD_BIT) & 1; + int epnum = usb_endpoint_num(&urb->ep->desc); + + /* no locking: HCD (i.e., we) own toggles, don't we? */ + usb_settoggle(urb->dev, epnum, 0, rcvtog); + usb_settoggle(urb->dev, epnum, 1, sndtog); + max3421_hcd->curr_urb = NULL; spin_lock_irqsave(&max3421_hcd->lock, flags); usb_hcd_unlink_urb_from_ep(hcd, urb);