Received: by 2002:a05:6a10:1287:0:0:0:0 with SMTP id d7csp3678645pxv; Mon, 26 Jul 2021 09:14:01 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzwm1ZLfXFhL54UDbvQ7KEVeHjhkz2AjO1XW8xzg2xE6YUM4wqU3mZ0Ai/wAz5rQd1cnZ5e X-Received: by 2002:a92:7d07:: with SMTP id y7mr13457557ilc.68.1627316040821; Mon, 26 Jul 2021 09:14:00 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1627316040; cv=none; d=google.com; s=arc-20160816; b=GAB1fVLh/f/dnfpgfmfQaee8gER7T3O5U3GrTolVjN9g9BBAP/5Vipo1tDe/4jWLKq /3zoklnBe9iwWDD1/xXF0msT/oRBkY9ThVk1b34+3UEA6gHZfT2cC/CyGY4bi1Iw2lIO R0gRD3r2MwLa+s9SI20AfSYu2nY21vJfvHWMpQ/uh5MXT6Y5IjDIqI3Bx3N9VnfkJA+Y fKuyGe3JwstNsHyhlPzeqb33uF9unVzGwARclBQQ46KzkWq99A9+z9mdQ+lttKcaw0fx SiM9ZWvsiZxQ7fhKfJxCAvvzHg6euAAvzmqtUK34PkI03qretQFC/IpA/WA4Rn9qpy37 NoVQ== 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=0FmLsnPwUbkVjF33URL3UEmZ75aUlZ2b5yVngU9216wxHvjpZ2VNjFXNoEpPFdPw8p mkAUf+8lMsZBnDn2sixxrClNyMiIAFjcbj04tgW+ED6wcrrEO4zMip555wthznvxZHJO XZ+z7qn1sDHcBcGs3XXMkmhz99LSUMDJSczw0KCaweh/SbORS07xC+vLuBBedH8GVv15 mhVuzR3yJFwP5+Im9iXfmWRmgmUi5OrvczOzJgW87g8Qd/ldi9XVL7dfDvOqYL5y6eGP AmmI72RyBvdoSgw3sOGTkaSzJk7mJ8qCfJSogVHmz1Dol35RNxb4YKL2tnUDGsnXvtxL QqMg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=LqKTBkRR; 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 u6si244832ioc.42.2021.07.26.09.13.48; Mon, 26 Jul 2021 09:14:00 -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=LqKTBkRR; 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 S233279AbhGZPcP (ORCPT + 99 others); Mon, 26 Jul 2021 11:32:15 -0400 Received: from mail.kernel.org ([198.145.29.99]:58654 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236179AbhGZPSI (ORCPT ); Mon, 26 Jul 2021 11:18:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id C095A60F70; Mon, 26 Jul 2021 15:58:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1627315115; bh=Z8xvYOwArq6z6cOpGIaDz6plqC40jynkMy5CihLFma8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LqKTBkRRMoYBuU/iNJN24Lzj1LwtcWqBKSibDXS2q5yIwSda9RddcAnVeoqduQjwZ w6yxkhK26c1rDtMYYkwFiD24HQiQvLPu0ta5CNGEBnNF597iM/xKlgqSEeVcRT2m7v p/qtywVe9vHdTu+2I6I0Kg36kWUik3Nzd2y7SQ6E= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Mark Tomlinson Subject: [PATCH 5.4 082/108] usb: max-3421: Prevent corruption of freed memory Date: Mon, 26 Jul 2021 17:39:23 +0200 Message-Id: <20210726153834.304065199@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210726153831.696295003@linuxfoundation.org> References: <20210726153831.696295003@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);