| From 2488f1dc4fb8df2660844245c3de2bddb1c04450 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 18 Jun 2020 11:21:25 +0800 |
| Subject: spi: spidev: fix a potential use-after-free in spidev_release() |
| |
| From: Zhenzhong Duan <zhenzhong.duan@gmail.com> |
| |
| [ Upstream commit 06096cc6c5a84ced929634b0d79376b94c65a4bd ] |
| |
| If an spi device is unbounded from the driver before the release |
| process, there will be an NULL pointer reference when it's |
| referenced in spi_slave_abort(). |
| |
| Fix it by checking it's already freed before reference. |
| |
| Signed-off-by: Zhenzhong Duan <zhenzhong.duan@gmail.com> |
| Link: https://lore.kernel.org/r/20200618032125.4650-2-zhenzhong.duan@gmail.com |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/spi/spidev.c | 20 ++++++++++---------- |
| 1 file changed, 10 insertions(+), 10 deletions(-) |
| |
| diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c |
| index 88d0976215fac..ac6bf1fbbfe68 100644 |
| --- a/drivers/spi/spidev.c |
| +++ b/drivers/spi/spidev.c |
| @@ -605,15 +605,20 @@ err_find_dev: |
| static int spidev_release(struct inode *inode, struct file *filp) |
| { |
| struct spidev_data *spidev; |
| + int dofree; |
| |
| mutex_lock(&device_list_lock); |
| spidev = filp->private_data; |
| filp->private_data = NULL; |
| |
| + spin_lock_irq(&spidev->spi_lock); |
| + /* ... after we unbound from the underlying device? */ |
| + dofree = (spidev->spi == NULL); |
| + spin_unlock_irq(&spidev->spi_lock); |
| + |
| /* last close? */ |
| spidev->users--; |
| if (!spidev->users) { |
| - int dofree; |
| |
| kfree(spidev->tx_buffer); |
| spidev->tx_buffer = NULL; |
| @@ -621,19 +626,14 @@ static int spidev_release(struct inode *inode, struct file *filp) |
| kfree(spidev->rx_buffer); |
| spidev->rx_buffer = NULL; |
| |
| - spin_lock_irq(&spidev->spi_lock); |
| - if (spidev->spi) |
| - spidev->speed_hz = spidev->spi->max_speed_hz; |
| - |
| - /* ... after we unbound from the underlying device? */ |
| - dofree = (spidev->spi == NULL); |
| - spin_unlock_irq(&spidev->spi_lock); |
| - |
| if (dofree) |
| kfree(spidev); |
| + else |
| + spidev->speed_hz = spidev->spi->max_speed_hz; |
| } |
| #ifdef CONFIG_SPI_SLAVE |
| - spi_slave_abort(spidev->spi); |
| + if (!dofree) |
| + spi_slave_abort(spidev->spi); |
| #endif |
| mutex_unlock(&device_list_lock); |
| |
| -- |
| 2.25.1 |
| |