Received: by 2002:a05:6a10:1287:0:0:0:0 with SMTP id d7csp3663643pxv; Mon, 26 Jul 2021 08:59:07 -0700 (PDT) X-Google-Smtp-Source: ABdhPJy4tICxTMNOapmYu0s6cWLYQM6HjlcH/xgGt5CD4BobUxpv3sLKwmX5DhZ80OHfjmAezjjP X-Received: by 2002:a02:90cb:: with SMTP id c11mr17539730jag.53.1627315147354; Mon, 26 Jul 2021 08:59:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1627315147; cv=none; d=google.com; s=arc-20160816; b=t+/GVLBKGqxo/FYQH5sSvzcfuTytWd7PWddzMSgDv3vDYsPLKjzDAinasATNh50vtL EpkyZun3Y49uOD7Phd+NQ5jCM2wkcjMHkeX6hy8YL66V8GoAF+LZDDT9K1I0vcI3sVCW PTscZmpxMnkSdQ2FacPQihzmQg+x6P9U+Z5LeWZ3AV9B1W3af9kZhaxqMvLi3ch41x49 5bdNxPInHGAx5fdoTQsEImMAAnJITT85e6ck4LMzIGjK2aM6rj0y6YkpVQ/r1NpDoTRR EqnlhV5h/NlehNxW1Wh79ilDhgGaCYxqDghQ+BVUpQXeT5KDi2ksW7X0iSHiynFASo/+ zMAA== 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=9ypV5HzP8R2a0yy4wD+Y4Goy01KSjzYGL2YsUUgldfY=; b=Py2YwMDd2E+S4Jm7PHPSwSIsZ6i5oLBhPEyXAFoxKO4rkQw3MbPIqCVbLQzDUKlzF0 lyou8OYTL5cG8jLSoOOS4ltbQisfketRoNnTh+rfxqENMTZF4IT4/B7xB8snLMWBux/i qK82qnR4ftQneuL88iy3PRfXT7nwaATCRPCBegnSVhhLmfaaqD8CiRqxBrsalPWbqPyq WIQEX9EGhnIURSm2jsOwtFtp5RW8RjC7owUyU6jNIWzjvzPGtZuwtvEx/BJAQDrDBUbg pf4El1Wy8TzmItOgJmtSuENsuYFW33JR8vPLRD1ovG4MzhEoNKrKHDl3QyiqmhkM9n2G zwKw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=QdXxl52+; 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 15si258730ilz.158.2021.07.26.08.58.55; Mon, 26 Jul 2021 08:59:07 -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=QdXxl52+; 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 S236284AbhGZPQl (ORCPT + 99 others); Mon, 26 Jul 2021 11:16:41 -0400 Received: from mail.kernel.org ([198.145.29.99]:49006 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236421AbhGZPJJ (ORCPT ); Mon, 26 Jul 2021 11:09:09 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id CBC6F60FC3; Mon, 26 Jul 2021 15:49:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1627314547; bh=el6tkVb4lJ9KT+q1In3s+lhL4jmAmJqbJ1PlydAWZVQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QdXxl52+sV+Uh9/jgUP3CMUzV54H53jw3E67vDmFhbg/vToccjZ2JVsWJCylLZMy3 f71N5DaiSPmqokhJ4QxsIp0ExADXnUglNJhwqroQUh1GdLOT8qF3t7CMEUqk7srPln 6Uxt4sjGWBXEGnNfH7F2cVoawoSRA9adJYBks+s4= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Mark Tomlinson Subject: [PATCH 4.14 66/82] usb: max-3421: Prevent corruption of freed memory Date: Mon, 26 Jul 2021 17:39:06 +0200 Message-Id: <20210726153830.317485226@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210726153828.144714469@linuxfoundation.org> References: <20210726153828.144714469@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 @@ -149,8 +149,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; @@ -488,39 +486,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); /* @@ -528,7 +504,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); } @@ -663,7 +638,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; @@ -773,7 +748,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; } @@ -781,7 +755,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; @@ -1376,6 +1350,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);