linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] spi: spidev: fix a race condition when accessing spidev->spi
@ 2023-01-05 12:40 Bartosz Golaszewski
  2023-01-05 12:41 ` [PATCH 2/2] spi: spidev: remove debug messages that access spidev->spi without locking Bartosz Golaszewski
  2023-01-05 13:52 ` [PATCH 1/2] spi: spidev: fix a race condition when accessing spidev->spi Mark Brown
  0 siblings, 2 replies; 5+ messages in thread
From: Bartosz Golaszewski @ 2023-01-05 12:40 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-spi, linux-kernel, Bartosz Golaszewski

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

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 sleeping lock. Using an RW semaphore
allows the syscalls to run concurrently unless protected otherwise. We
take it for writing only when setting spidev->spi to null, while
everywhere else it's only taken for reading. This assures that it will
be dropped only once all currently executed syscalls have returned.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/spi/spidev.c | 35 +++++++++++++++++++----------------
 1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 6313e7d0cdf8..b71620f64ec9 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/property.h>
+#include <linux/rwsem.h>
 #include <linux/slab.h>
 #include <linux/compat.h>
 
@@ -68,7 +69,7 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256);
 
 struct spidev_data {
 	dev_t			devt;
-	spinlock_t		spi_lock;
+	struct rw_semaphore	sem;
 	struct spi_device	*spi;
 	struct list_head	device_entry;
 
@@ -95,9 +96,8 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message)
 	int status;
 	struct spi_device *spi;
 
-	spin_lock_irq(&spidev->spi_lock);
+	down_read(&spidev->sem);
 	spi = spidev->spi;
-	spin_unlock_irq(&spidev->spi_lock);
 
 	if (spi == NULL)
 		status = -ESHUTDOWN;
@@ -107,6 +107,7 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message)
 	if (status == 0)
 		status = message->actual_length;
 
+	up_read(&spidev->sem);
 	return status;
 }
 
@@ -359,12 +360,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);
+	down_read(&spidev->sem);
 	spi = spi_dev_get(spidev->spi);
-	spin_unlock_irq(&spidev->spi_lock);
-
-	if (spi == NULL)
+	if (spi == NULL) {
+		up_read(&spidev->sem);
 		return -ESHUTDOWN;
+	}
 
 	/* use the buffer lock here for triple duty:
 	 *  - prevent I/O (from us) so calling spi_setup() is safe;
@@ -508,6 +509,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 
 	mutex_unlock(&spidev->buf_lock);
 	spi_dev_put(spi);
+	up_read(&spidev->sem);
 	return retval;
 }
 
@@ -529,12 +531,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);
+	down_read(&spidev->sem);
 	spi = spi_dev_get(spidev->spi);
-	spin_unlock_irq(&spidev->spi_lock);
-
-	if (spi == NULL)
+	if (spi == NULL) {
+		up_read(&spidev->sem);
 		return -ESHUTDOWN;
+	}
 
 	/* SPI_IOC_MESSAGE needs the buffer locked "normally" */
 	mutex_lock(&spidev->buf_lock);
@@ -561,6 +563,7 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd,
 done:
 	mutex_unlock(&spidev->buf_lock);
 	spi_dev_put(spi);
+	up_read(&spidev->sem);
 	return retval;
 }
 
@@ -640,10 +643,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);
+	down_read(&spidev->sem);
 	/* ... after we unbound from the underlying device? */
 	dofree = (spidev->spi == NULL);
-	spin_unlock_irq(&spidev->spi_lock);
+	up_read(&spidev->sem);
 
 	/* last close? */
 	spidev->users--;
@@ -776,7 +779,7 @@ static int spidev_probe(struct spi_device *spi)
 
 	/* Initialize the driver data */
 	spidev->spi = spi;
-	spin_lock_init(&spidev->spi_lock);
+	init_rwsem(&spidev->sem);
 	mutex_init(&spidev->buf_lock);
 
 	INIT_LIST_HEAD(&spidev->device_entry);
@@ -821,9 +824,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);
+	down_write(&spidev->sem);
 	spidev->spi = NULL;
-	spin_unlock_irq(&spidev->spi_lock);
+	up_write(&spidev->sem);
 
 	list_del(&spidev->device_entry);
 	device_destroy(spidev_class, spidev->devt);
-- 
2.37.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] spi: spidev: remove debug messages that access spidev->spi without locking
  2023-01-05 12:40 [PATCH 1/2] spi: spidev: fix a race condition when accessing spidev->spi Bartosz Golaszewski
@ 2023-01-05 12:41 ` Bartosz Golaszewski
  2023-01-05 13:52 ` [PATCH 1/2] spi: spidev: fix a race condition when accessing spidev->spi Mark Brown
  1 sibling, 0 replies; 5+ messages in thread
From: Bartosz Golaszewski @ 2023-01-05 12:41 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-spi, linux-kernel, Bartosz Golaszewski

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

The two debug messages in spidev_open() dereference spidev->spi without
taking the semaphore and without checking if it's not null. This can
lead to a crash. Drop the messages as they're not needed - the user-space
will get informed about ENOMEM with the syscall return value.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/spi/spidev.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index b71620f64ec9..29c6344ee8e8 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -604,7 +604,6 @@ static int spidev_open(struct inode *inode, struct file *filp)
 	if (!spidev->tx_buffer) {
 		spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL);
 		if (!spidev->tx_buffer) {
-			dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
 			status = -ENOMEM;
 			goto err_find_dev;
 		}
@@ -613,7 +612,6 @@ static int spidev_open(struct inode *inode, struct file *filp)
 	if (!spidev->rx_buffer) {
 		spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL);
 		if (!spidev->rx_buffer) {
-			dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
 			status = -ENOMEM;
 			goto err_alloc_rx_buf;
 		}
-- 
2.37.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] spi: spidev: fix a race condition when accessing spidev->spi
  2023-01-05 12:40 [PATCH 1/2] spi: spidev: fix a race condition when accessing spidev->spi Bartosz Golaszewski
  2023-01-05 12:41 ` [PATCH 2/2] spi: spidev: remove debug messages that access spidev->spi without locking Bartosz Golaszewski
@ 2023-01-05 13:52 ` Mark Brown
  2023-01-05 14:30   ` Bartosz Golaszewski
  1 sibling, 1 reply; 5+ messages in thread
From: Mark Brown @ 2023-01-05 13:52 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: linux-spi, linux-kernel, Bartosz Golaszewski

[-- Attachment #1: Type: text/plain, Size: 411 bytes --]

On Thu, Jan 05, 2023 at 01:40:59PM +0100, Bartosz Golaszewski wrote:

> can replace the spinlock with a sleeping lock. Using an RW semaphore
> allows the syscalls to run concurrently unless protected otherwise. We

I'm not sure this is important or useful, there's not a lot that can
practically happen concurrently when we get to actually interacting with
the device and it's making the code a bit less clear.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] spi: spidev: fix a race condition when accessing spidev->spi
  2023-01-05 13:52 ` [PATCH 1/2] spi: spidev: fix a race condition when accessing spidev->spi Mark Brown
@ 2023-01-05 14:30   ` Bartosz Golaszewski
  2023-01-05 14:43     ` Mark Brown
  0 siblings, 1 reply; 5+ messages in thread
From: Bartosz Golaszewski @ 2023-01-05 14:30 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-spi, linux-kernel, Bartosz Golaszewski

On Thu, Jan 5, 2023 at 2:52 PM Mark Brown <broonie@kernel.org> wrote:
>
> On Thu, Jan 05, 2023 at 01:40:59PM +0100, Bartosz Golaszewski wrote:
>
> > can replace the spinlock with a sleeping lock. Using an RW semaphore
> > allows the syscalls to run concurrently unless protected otherwise. We
>
> I'm not sure this is important or useful, there's not a lot that can
> practically happen concurrently when we get to actually interacting with
> the device and it's making the code a bit less clear.

You suggest to just use a mutex instead?

Bart

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] spi: spidev: fix a race condition when accessing spidev->spi
  2023-01-05 14:30   ` Bartosz Golaszewski
@ 2023-01-05 14:43     ` Mark Brown
  0 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2023-01-05 14:43 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: linux-spi, linux-kernel, Bartosz Golaszewski

[-- Attachment #1: Type: text/plain, Size: 401 bytes --]

On Thu, Jan 05, 2023 at 03:30:47PM +0100, Bartosz Golaszewski wrote:
> On Thu, Jan 5, 2023 at 2:52 PM Mark Brown <broonie@kernel.org> wrote:

> > I'm not sure this is important or useful, there's not a lot that can
> > practically happen concurrently when we get to actually interacting with
> > the device and it's making the code a bit less clear.

> You suggest to just use a mutex instead?

Yeah.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-01-05 14:44 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-05 12:40 [PATCH 1/2] spi: spidev: fix a race condition when accessing spidev->spi Bartosz Golaszewski
2023-01-05 12:41 ` [PATCH 2/2] spi: spidev: remove debug messages that access spidev->spi without locking Bartosz Golaszewski
2023-01-05 13:52 ` [PATCH 1/2] spi: spidev: fix a race condition when accessing spidev->spi Mark Brown
2023-01-05 14:30   ` Bartosz Golaszewski
2023-01-05 14:43     ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).