Received: by 2002:a25:4158:0:0:0:0:0 with SMTP id o85csp455785yba; Wed, 15 May 2019 04:25:10 -0700 (PDT) X-Google-Smtp-Source: APXvYqzLMmfsMjTRqJe6/Zuydt0XGCpp7iQdFbYXWuuNBN5W0WkCzBD65MXZS6iok/FYDaGDxFiP X-Received: by 2002:a63:5c45:: with SMTP id n5mr1163795pgm.172.1557919510078; Wed, 15 May 2019 04:25:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1557919510; cv=none; d=google.com; s=arc-20160816; b=GLCf2RXO/WMPM9oeCa4So0hNChWU2QHJbQbzwhjSZZLJVD4C12hL+gC7HK3OPrqar0 LzLpP/brHa+gthVFaoTuY97bjqIaw19dlFQkJSj95nIw5mz8b0Whuvm5VT+qoYX2CZ01 AM0XUj+BtTB7TiYsO4LHAgMzyZeQ2FmolVTymZciwxDenX/tGOmD+txmcUXLe5cG7+BP ruMXO9Su/ThZdTBGEOQkLXz5Q2EpbdZ/RwGFqezgSHXwWXObCvBQCXfbI0Jts4yiL9CQ fhO6nBmbGf36IZNeWY36cySrYJntZEWn9BvSghYK3ngbFHw7oFbPtS5/3ACANHsw9s77 fNJA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=uAh77bHRTU60edg7mOpz8gRUVWdCvIS0Di1ba6msz+s=; b=tUxBKqY0Pc6GdDr3gAsSvuOsYBfhBMflsFK86YP7VkMqSzPT2h0KAMmQ/MkdJNbtA9 SeAgWULyx9gYARK+RvJeuOarSStkbGOXAPEdpNDw70BL6fwtVaOPeUAO0LTDl2RLZBZ7 XZn6G6XEAD9ysfE/8a51PQ1CLsH/F6HiKODrvl0BuRJ641JzDm6MrbVXjDcZLUy6GAfJ Vhle9BbAJxC+6aJ7fkny0iWK6SeaVDs6e4cJ4o3gg+cmKxCzgMyEmAwa9Tls37Uc12Ok TvfSy76BHWEAllN4oWKvKWNHXVqrFYiRg2h3MjAxNU5W44Vlyx3AmUxzNKVRelCBv386 5nEw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=KvpnudDF; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v4si1504607plp.404.2019.05.15.04.24.54; Wed, 15 May 2019 04:25:10 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=KvpnudDF; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731500AbfEOLWj (ORCPT + 99 others); Wed, 15 May 2019 07:22:39 -0400 Received: from mail.kernel.org ([198.145.29.99]:32792 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731489AbfEOLWh (ORCPT ); Wed, 15 May 2019 07:22:37 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 32C1D206BF; Wed, 15 May 2019 11:22:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1557919356; bh=U+cZlY8muUchaepQ07mFSd7U+l0+CHSxVPLR5nRyDus=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KvpnudDFlTOq5iXIZDLUS0ZrYMttEeBRwdAt4s1JvFHQGS3CvIsWEDpOLRWLyTiYt I6T7PscKV4MyIYeBM1Y5I7NkOvoH68xEw3T8Z+5vheMJjKM63oWe8SUQd06qvXXpN2 v9CxmSEi/VihX9u1Pir7sfohI1SKwS0d8Oyd13g8= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Johan Hovold Subject: [PATCH 4.19 008/113] USB: serial: fix unthrottle races Date: Wed, 15 May 2019 12:54:59 +0200 Message-Id: <20190515090654.083402466@linuxfoundation.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190515090652.640988966@linuxfoundation.org> References: <20190515090652.640988966@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Johan Hovold commit 3f5edd58d040bfa4b74fb89bc02f0bc6b9cd06ab upstream. Fix two long-standing bugs which could potentially lead to memory corruption or leave the port throttled until it is reopened (on weakly ordered systems), respectively, when read-URB completion races with unthrottle(). First, the URB must not be marked as free before processing is complete to prevent it from being submitted by unthrottle() on another CPU. CPU 1 CPU 2 ================ ================ complete() unthrottle() process_urb(); smp_mb__before_atomic(); set_bit(i, free); if (test_and_clear_bit(i, free)) submit_urb(); Second, the URB must be marked as free before checking the throttled flag to prevent unthrottle() on another CPU from failing to observe that the URB needs to be submitted if complete() sees that the throttled flag is set. CPU 1 CPU 2 ================ ================ complete() unthrottle() set_bit(i, free); throttled = 0; smp_mb__after_atomic(); smp_mb(); if (throttled) if (test_and_clear_bit(i, free)) return; submit_urb(); Note that test_and_clear_bit() only implies barriers when the test is successful. To handle the case where the URB is still in use an explicit barrier needs to be added to unthrottle() for the second race condition. Fixes: d83b405383c9 ("USB: serial: add support for multiple read urbs") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/generic.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -376,6 +376,7 @@ void usb_serial_generic_read_bulk_callba struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; unsigned long flags; + bool stopped = false; int status = urb->status; int i; @@ -383,33 +384,51 @@ void usb_serial_generic_read_bulk_callba if (urb == port->read_urbs[i]) break; } - set_bit(i, &port->read_urbs_free); dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i, urb->actual_length); switch (status) { case 0: + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, + data); + port->serial->type->process_read_urb(urb); break; case -ENOENT: case -ECONNRESET: case -ESHUTDOWN: dev_dbg(&port->dev, "%s - urb stopped: %d\n", __func__, status); - return; + stopped = true; + break; case -EPIPE: dev_err(&port->dev, "%s - urb stopped: %d\n", __func__, status); - return; + stopped = true; + break; default: dev_dbg(&port->dev, "%s - nonzero urb status: %d\n", __func__, status); - goto resubmit; + break; } - usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); - port->serial->type->process_read_urb(urb); + /* + * Make sure URB processing is done before marking as free to avoid + * racing with unthrottle() on another CPU. Matches the barriers + * implied by the test_and_clear_bit() in + * usb_serial_generic_submit_read_urb(). + */ + smp_mb__before_atomic(); + set_bit(i, &port->read_urbs_free); + /* + * Make sure URB is marked as free before checking the throttled flag + * to avoid racing with unthrottle() on another CPU. Matches the + * smp_mb() in unthrottle(). + */ + smp_mb__after_atomic(); + + if (stopped) + return; -resubmit: /* Throttle the device if requested by tty */ spin_lock_irqsave(&port->lock, flags); port->throttled = port->throttle_req; @@ -484,6 +503,12 @@ void usb_serial_generic_unthrottle(struc port->throttled = port->throttle_req = 0; spin_unlock_irq(&port->lock); + /* + * Matches the smp_mb__after_atomic() in + * usb_serial_generic_read_bulk_callback(). + */ + smp_mb(); + if (was_throttled) usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); }