[PATCH 5.4 048/168] ASoC: SOF: trace: fix unconditional free in trace release
From: Greg Kroah-Hartman
Date: Tue Apr 28 2020 - 14:37:23 EST
From: Kai Vehmanen <kai.vehmanen@xxxxxxxxxxxxxxx>
[ Upstream commit e6110114d18d330c05fd6de9f31283fd086a5a3a ]
Check if DMA pages were successfully allocated in initialization
before calling free. For many types of memory (like sgbufs)
the extra free is harmless, but not all backends track allocation
state, so add an explicit check.
Signed-off-by: Kai Vehmanen <kai.vehmanen@xxxxxxxxxxxxxxx>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@xxxxxxxxxxxxxxx>
Link: https://lore.kernel.org/r/20200124213625.30186-5-pierre-louis.bossart@xxxxxxxxxxxxxxx
Signed-off-by: Mark Brown <broonie@xxxxxxxxxx>
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---
sound/soc/sof/trace.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c
index 4c3cff031fd66..fd6f5913782bf 100644
--- a/sound/soc/sof/trace.c
+++ b/sound/soc/sof/trace.c
@@ -328,7 +328,10 @@ void snd_sof_free_trace(struct snd_sof_dev *sdev)
{
snd_sof_release_trace(sdev);
- snd_dma_free_pages(&sdev->dmatb);
- snd_dma_free_pages(&sdev->dmatp);
+ if (sdev->dma_trace_pages) {
+ snd_dma_free_pages(&sdev->dmatb);
+ snd_dma_free_pages(&sdev->dmatp);
+ sdev->dma_trace_pages = 0;
+ }
}
EXPORT_SYMBOL(snd_sof_free_trace);
--
2.20.1
ansport.c:937
This bug occurs when cancellation of the S-G transfer races with
transfer completion. When that happens, usb_sg_cancel() may continue
to access the transfer's URBs after usb_sg_wait() has freed them.
The bug is caused by the fact that usb_sg_cancel() does not take any
sort of reference to the transfer, and so there is nothing to prevent
the URBs from being deallocated while the routine is trying to use
them. The fix is to take such a reference by incrementing the
transfer's io->count field while the cancellation is in progres and
decrementing it afterward. The transfer's URBs are not deallocated
until io->complete is triggered, which happens when io->count reaches
zero.
Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
Reported-and-tested-by: Kyungtae Kim <kt0755@xxxxxxxxx>
CC: <stable@xxxxxxxxxxxxxxx>
Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.2003281615140.14837-100000@xxxxxxxxxxxxxxxxxxxx
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/usb/core/message.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -588,12 +588,13 @@ void usb_sg_cancel(struct usb_sg_request
int i, retval;
spin_lock_irqsave(&io->lock, flags);
- if (io->status) {
+ if (io->status || io->count == 0) {
spin_unlock_irqrestore(&io->lock, flags);
return;
}
/* shut everything down */
io->status = -ECONNRESET;
+ io->count++; /* Keep the request alive until we're done */
spin_unlock_irqrestore(&io->lock, flags);
for (i = io->entries - 1; i >= 0; --i) {
@@ -607,6 +608,12 @@ void usb_sg_cancel(struct usb_sg_request
dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
__func__, retval);
}
+
+ spin_lock_irqsave(&io->lock, flags);
+ io->count--;
+ if (!io->count)
+ complete(&io->complete);
+ spin_unlock_irqrestore(&io->lock, flags);
}
EXPORT_SYMBOL_GPL(usb_sg_cancel);