public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>,
	Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>,
	linux-spi@vger.kernel.org
Subject: [PATCH AUTOSEL 5.4 09/16] spi: spidev: fix a race condition when accessing spidev->spi
Date: Mon, 16 Jan 2023 09:05:12 -0500	[thread overview]
Message-ID: <20230116140520.116257-9-sashal@kernel.org> (raw)
In-Reply-To: <20230116140520.116257-1-sashal@kernel.org>

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

[ 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 <bartosz.golaszewski@linaro.org>
Link: https://lore.kernel.org/r/20230106100719.196243-1-brgl@bgdev.pl
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 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 be503a0e6ef7..a360dabdcb8b 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -66,7 +66,7 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS);
 
 struct spidev_data {
 	dev_t			devt;
-	spinlock_t		spi_lock;
+	struct mutex		spi_lock;
 	struct spi_device	*spi;
 	struct list_head	device_entry;
 
@@ -93,9 +93,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;
@@ -105,6 +104,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;
 }
 
@@ -355,12 +355,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;
@@ -485,6 +485,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;
 }
 
@@ -506,12 +507,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);
@@ -538,6 +539,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;
 }
 
@@ -616,10 +618,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--;
@@ -746,7 +748,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);
@@ -791,9 +793,9 @@ static int 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


  parent reply	other threads:[~2023-01-16 14:15 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-16 14:05 [PATCH AUTOSEL 5.4 01/16] cpufreq: Add Tegra234 to cpufreq-dt-platdev blocklist Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 02/16] ASoC: fsl_micfil: Correct the number of steps on SX controls Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 03/16] drm: Add orientation quirk for Lenovo ideapad D330-10IGL Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 04/16] s390/debug: add _ASM_S390_ prefix to header guard Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 05/16] arm64/mm: Define dummy pud_user_exec() when using 2-level page-table Sasha Levin
2023-01-16 18:30   ` Catalin Marinas
2023-01-23  0:59     ` Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 06/16] cpufreq: armada-37xx: stop using 0 as NULL pointer Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 07/16] ASoC: fsl_ssi: Rename AC'97 streams to avoid collisions with AC'97 CODEC Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 08/16] ASoC: fsl-asoc-card: Fix naming of AC'97 CODEC widgets Sasha Levin
2023-01-16 14:05 ` Sasha Levin [this message]
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 10/16] spi: spidev: remove debug messages that access spidev->spi without locking Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 11/16] KVM: s390: interrupt: use READ_ONCE() before cmpxchg() Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 12/16] scsi: hisi_sas: Set a port invalid only if there are no devices attached when refreshing port id Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 13/16] platform/x86: touchscreen_dmi: Add info for the CSL Panther Tab HD Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 14/16] platform/x86: asus-nb-wmi: Add alternate mapping for KEY_SCREENLOCK Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 15/16] platform/x86: asus-wmi: Ignore fan on E410MA Sasha Levin
2023-01-16 14:05 ` [PATCH AUTOSEL 5.4 16/16] lockref: stop doing cpu_relax in the cmpxchg loop Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230116140520.116257-9-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=bartosz.golaszewski@linaro.org \
    --cc=broonie@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-spi@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox