Commit b26a193b authored by Zhenzhong Duan's avatar Zhenzhong Duan Committed by Khalid Elmously

spi: spidev: fix a potential use-after-free in spidev_release()

BugLink: https://bugs.launchpad.net/bugs/1888690

[ Upstream commit 06096cc6 ]

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: default avatarZhenzhong Duan <zhenzhong.duan@gmail.com>
Link: https://lore.kernel.org/r/20200618032125.4650-2-zhenzhong.duan@gmail.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarKamal Mostafa <kamal@canonical.com>
Signed-off-by: default avatarKhalid Elmously <khalid.elmously@canonical.com>
parent 8dc36822
...@@ -635,15 +635,20 @@ static int spidev_open(struct inode *inode, struct file *filp) ...@@ -635,15 +635,20 @@ static int spidev_open(struct inode *inode, struct file *filp)
static int spidev_release(struct inode *inode, struct file *filp) static int spidev_release(struct inode *inode, struct file *filp)
{ {
struct spidev_data *spidev; struct spidev_data *spidev;
int dofree;
mutex_lock(&device_list_lock); mutex_lock(&device_list_lock);
spidev = filp->private_data; spidev = filp->private_data;
filp->private_data = NULL; 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? */ /* last close? */
spidev->users--; spidev->users--;
if (!spidev->users) { if (!spidev->users) {
int dofree;
kfree(spidev->tx_buffer); kfree(spidev->tx_buffer);
spidev->tx_buffer = NULL; spidev->tx_buffer = NULL;
...@@ -651,19 +656,14 @@ static int spidev_release(struct inode *inode, struct file *filp) ...@@ -651,19 +656,14 @@ static int spidev_release(struct inode *inode, struct file *filp)
kfree(spidev->rx_buffer); kfree(spidev->rx_buffer);
spidev->rx_buffer = NULL; 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) if (dofree)
kfree(spidev); kfree(spidev);
else
spidev->speed_hz = spidev->spi->max_speed_hz;
} }
#ifdef CONFIG_SPI_SLAVE #ifdef CONFIG_SPI_SLAVE
spi_slave_abort(spidev->spi); if (!dofree)
spi_slave_abort(spidev->spi);
#endif #endif
mutex_unlock(&device_list_lock); mutex_unlock(&device_list_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment