Received: by 2002:a05:6a10:1287:0:0:0:0 with SMTP id d7csp3699005pxv; Mon, 26 Jul 2021 09:40:36 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyKE1SUCw77eM8jVa6uqOAEIoeSwWqR9qI+xij7mSre8XYT/mvXhvkTlLus2kbdO7MzzZSX X-Received: by 2002:a05:6402:2919:: with SMTP id ee25mr23077749edb.222.1627317517311; Mon, 26 Jul 2021 09:38:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1627317517; cv=none; d=google.com; s=arc-20160816; b=YHTRiPcREm+UacoLCpxZOnfIUrteqcZuxzpWBo+Ixb2u6XjUECwP/OXZaoDVLBJOHI LpVjZySX1i8gGSbZiqNxx4ffvKbAU5SUtXl9e8k+A3nWh5QnQrUzinD3prT7fdeBBzft 9zx+rXoXy3nFO07acmu8SP6+YWoMph5Z/WHo8pqZvAHTljCIqT4j6kpoQ/9CJDQ3pZPb rtHeTc5emGR9Ez3Y6FUx6cJZqMjzFE4CW7s91XQx9ktppnhulX0/da8P9WfINESyAIFu VmTGsZuEL8eS1B6x3mn7RKH33uy+ZT38YcMBDECjyfw8jzxeQrV8tlMCFFJYzfSN/q8Z ZSnA== 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=T9qvOwlIXwucmgnp7SiHHshA/NTMXuybakcDGkGA15Ejx46/1pEESW2JFKUeHFKW0o xHjtGsnCpDb9cNq4Sw3zfsPK1XPgVe9W1iGgs9U49sFXTUm1p37Vkrau13K9Ougu2fMy 173LPIOW2yS17iXCkXB9oShwrACM92h89Mum5GSKPY5Foz8eq70yIafW1hy/Fweefucf Vz8sJ92rRSsfMFDZctAqB6vbvCfXvUWMuUgeFN3EV0P4NbjqptXSj+IDVP9t+NG59U+b S/MI+MK1n4CaW0B12sBcJdRQjAD6+CkZAZhW5knqwYeVtWeQ8wAN9qRV9FjGdHrfpm06 Xitg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b="R/Bnaz9l"; 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 w5si450475edv.200.2021.07.26.09.38.14; Mon, 26 Jul 2021 09:38:37 -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="R/Bnaz9l"; 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 S240553AbhGZPzi (ORCPT + 99 others); Mon, 26 Jul 2021 11:55:38 -0400 Received: from mail.kernel.org ([198.145.29.99]:50556 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234393AbhGZPda (ORCPT ); Mon, 26 Jul 2021 11:33:30 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 1DB6060EB2; Mon, 26 Jul 2021 16:13:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1627316039; bh=Z8xvYOwArq6z6cOpGIaDz6plqC40jynkMy5CihLFma8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=R/Bnaz9l0qExNGuNy1qteX7bnEJ1UZ3W0mjjguSwrXt7vKmY7+E01Tpu2caFcwmVd Fp9Cddb7GlMzLrTCkBlirUsPXjMN5DdPQJUszJamkNTAaJ0cIJC80sm76Aa5jfXhaA eMNJtzIJiU9qcB/jUkhKMtH6WlX2gYos5Rr1MrPY= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Mark Tomlinson Subject: [PATCH 5.13 164/223] usb: max-3421: Prevent corruption of freed memory Date: Mon, 26 Jul 2021 17:39:16 +0200 Message-Id: <20210726153851.574633812@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210726153846.245305071@linuxfoundation.org> References: <20210726153846.245305071@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);