Received: by 2002:a05:6358:a55:b0:ec:fcf4:3ecf with SMTP id 21csp3387769rwb; Mon, 16 Jan 2023 07:23:53 -0800 (PST) X-Google-Smtp-Source: AMrXdXuJjxWIh4Y3Nr8AkE492uiQqGwWDNt0e5UQa3WsQyeJtGJDI1cLxa6vSgYD4VryIFaMWMs7 X-Received: by 2002:a05:6a21:1011:b0:b8:9c31:f4d9 with SMTP id nk17-20020a056a21101100b000b89c31f4d9mr2023756pzb.29.1673882632965; Mon, 16 Jan 2023 07:23:52 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1673882632; cv=none; d=google.com; s=arc-20160816; b=hQ8h2/iYbcwwW0qNaoOR3LnRm5Pkopwp8x5hgB5PmtvxJbjygrJYVeF47kwhU2Z9Yi DuKvPNj0FUNrQ3UGSGMwc8rVIIQ3FBSkM0ChWTFD6wolVunCxThkFfLWgZ9SovK1Ebpi BN0HISp1NjXAaz68DGn560VdpL402zyTNG+E3EOzRH/dxNlFc1N3kDc4SAzvm53tJVxN LC7+p3XEDOJAt/aZQ0J8bsd2liJA8LNwU0fzxrW+e0LdDeAln1ZTUj4Nrz4tccL3tvyS hzQqVXFi+nRn20cw4ga5GKS0k3QS8ilgtwdqlbG8HJo6lZfGNw1m974lH9OS+xnepgux mrRw== 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 :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=SdVkf2FMsrNJ3YpuXKXbH9DPAQ4owOL9+Vufv0GZ+7s=; b=qgVUmL+tzV0VFM7lrf/LBmXSw2QEy+c+tzoUqp3zcXY04JFrR+hwjOfAFsAY++UD8n tT3QYRjcmf/ZpLqXIrKqj6WH/JRGdhYz/Lb1kwEbuOf+psx5ITw3EFhwcB7NgYKgtixg CRl8xitugdsn5E7rYStfntYUjkeA6pC9XveOz9TBf0EQuyiQYE7CiaDv4o7j1p5qS9I5 UkDQD9TH5nYMN04Muzpd3kMo25yflmLZsUpb/W6D71KUt3O2ugv0lmTHYcsGhChzUKOE 6iMRnv91kN99Uu3qMi6Ul5r3isU1hayR8FL1n78M9pWGrsgXmANOPMiY3MZg9DZGF/+P l/hg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=mvZdCl4q; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id v24-20020a634818000000b0049876520724si28088473pga.303.2023.01.16.07.23.46; Mon, 16 Jan 2023 07:23:52 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=mvZdCl4q; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231992AbjAPOHe (ORCPT + 50 others); Mon, 16 Jan 2023 09:07:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44358 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231723AbjAPOGd (ORCPT ); Mon, 16 Jan 2023 09:06:33 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6131B233E2; Mon, 16 Jan 2023 06:03:28 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id E931960FDA; Mon, 16 Jan 2023 14:03:27 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id AF182C433EF; Mon, 16 Jan 2023 14:03:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1673877807; bh=2NGod0pvuVryvaydk2DIixADB68TdDKkZV4cb1jjPZQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mvZdCl4qeCqPEZdkBKiU1YK7SZBeTNOKbVBqPH3Vkh5MCgfHg4Uv8gKlyZQU+5qC1 NB3P8AEnNcHI7HS6x7ziaB5VmkO3bFw3Lmi4S0ZltX7TaXibpd8pV8DdoFNnvzSQwu OyvLHCoDXMJM1OWPPUj8oN2qxL2Kz7V8Z775IljM7cfTyKHG2vgDyw+/DkNMm52cFm BNl6+CTgdlH8zcthwBdtG3pPvaDpGVu2NuAlAOZP3mKfkSNg01OT7ThYaZzk+GbnKZ gxb05mofbTdzwXafrX4FlttWdrAXeBhj9DVMZUYpymprgeBYgjrUK4zcIVlHz80xrf jB7fjq5ldFwPA== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Bartosz Golaszewski , Mark Brown , Sasha Levin , linux-spi@vger.kernel.org Subject: [PATCH AUTOSEL 6.1 38/53] spi: spidev: fix a race condition when accessing spidev->spi Date: Mon, 16 Jan 2023 09:01:38 -0500 Message-Id: <20230116140154.114951-38-sashal@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20230116140154.114951-1-sashal@kernel.org> References: <20230116140154.114951-1-sashal@kernel.org> MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-7.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Bartosz Golaszewski [ Upstream commit a720416d94634068951773cb9e9d6f1b73769e5b ] There's a spinlock in place that is taken in file_operations callbacks whenever we check if spidev->spi is still alive (not null). It's also taken when spidev->spi is set to NULL in remove(). This however doesn't protect the code against driver unbind event while one of the syscalls is still in progress. To that end we need a lock taken continuously as long as we may still access spidev->spi. As both the file ops and the remove callback are never called from interrupt context, we can replace the spinlock with a mutex. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230106100719.196243-1-brgl@bgdev.pl Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spidev.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 6313e7d0cdf8..42aaaca67265 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -68,7 +68,7 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256); struct spidev_data { dev_t devt; - spinlock_t spi_lock; + struct mutex spi_lock; struct spi_device *spi; struct list_head device_entry; @@ -95,9 +95,8 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message) int status; struct spi_device *spi; - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); spi = spidev->spi; - spin_unlock_irq(&spidev->spi_lock); if (spi == NULL) status = -ESHUTDOWN; @@ -107,6 +106,7 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message) if (status == 0) status = message->actual_length; + mutex_unlock(&spidev->spi_lock); return status; } @@ -359,12 +359,12 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) * we issue this ioctl. */ spidev = filp->private_data; - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); spi = spi_dev_get(spidev->spi); - spin_unlock_irq(&spidev->spi_lock); - - if (spi == NULL) + if (spi == NULL) { + mutex_unlock(&spidev->spi_lock); return -ESHUTDOWN; + } /* use the buffer lock here for triple duty: * - prevent I/O (from us) so calling spi_setup() is safe; @@ -508,6 +508,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) mutex_unlock(&spidev->buf_lock); spi_dev_put(spi); + mutex_unlock(&spidev->spi_lock); return retval; } @@ -529,12 +530,12 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd, * we issue this ioctl. */ spidev = filp->private_data; - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); spi = spi_dev_get(spidev->spi); - spin_unlock_irq(&spidev->spi_lock); - - if (spi == NULL) + if (spi == NULL) { + mutex_unlock(&spidev->spi_lock); return -ESHUTDOWN; + } /* SPI_IOC_MESSAGE needs the buffer locked "normally" */ mutex_lock(&spidev->buf_lock); @@ -561,6 +562,7 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd, done: mutex_unlock(&spidev->buf_lock); spi_dev_put(spi); + mutex_unlock(&spidev->spi_lock); return retval; } @@ -640,10 +642,10 @@ static int spidev_release(struct inode *inode, struct file *filp) spidev = filp->private_data; filp->private_data = NULL; - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); /* ... after we unbound from the underlying device? */ dofree = (spidev->spi == NULL); - spin_unlock_irq(&spidev->spi_lock); + mutex_unlock(&spidev->spi_lock); /* last close? */ spidev->users--; @@ -776,7 +778,7 @@ static int spidev_probe(struct spi_device *spi) /* Initialize the driver data */ spidev->spi = spi; - spin_lock_init(&spidev->spi_lock); + mutex_init(&spidev->spi_lock); mutex_init(&spidev->buf_lock); INIT_LIST_HEAD(&spidev->device_entry); @@ -821,9 +823,9 @@ static void spidev_remove(struct spi_device *spi) /* prevent new opens */ mutex_lock(&device_list_lock); /* make sure ops on existing fds can abort cleanly */ - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); spidev->spi = NULL; - spin_unlock_irq(&spidev->spi_lock); + mutex_unlock(&spidev->spi_lock); list_del(&spidev->device_entry); device_destroy(spidev_class, spidev->devt); -- 2.35.1