Hi! > [ Upstream commit 7dd2dd4ff9f3abda601f22b9d01441a0869d20d7 ] > > When user calls dmaengine_terminate_sync, the driver will clean up any > remaining descriptors for all the pending or active transfers that had > previously been submitted. However, this might happen whilst the tasklet is > invoking the DMA callback for the last finished transfer, so by the time it > returns and takes over the channel's spinlock, the list of completed > descriptors it was traversing is no longer valid. This leads to a > read-after-free situation. > > Fix it by signalling whether a user-triggered termination has happened by > means of a boolean variable. I see the variable is cleared and tested under spinlock, but it is set without any locking. Do we need to take the spinlock, too? Best regards, Pavel > @@ -1049,6 +1051,13 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan) > /* Run any dependencies, then free the descriptor */ > dma_run_dependencies(&desc->async_tx); > xilinx_dma_free_tx_descriptor(chan, desc); > + > + /* > + * While we ran a callback the user called a terminate function, > + * which takes care of cleaning up any remaining descriptors > + */ > + if (chan->terminating) > + break; > } > > spin_unlock_irqrestore(&chan->lock, flags); > @@ -1965,6 +1974,8 @@ static dma_cookie_t xilinx_dma_tx_submit(struct dma_async_tx_descriptor *tx) > if (desc->cyclic) > chan->cyclic = true; > > + chan->terminating = false; > + > spin_unlock_irqrestore(&chan->lock, flags); > > return cookie; > @@ -2436,6 +2447,7 @@ static int xilinx_dma_terminate_all(struct dma_chan *dchan) > > xilinx_dma_chan_reset(chan); > /* Remove and free all of the descriptors in the lists */ > + chan->terminating = true; > xilinx_dma_free_descriptors(chan); > chan->idle = true; > -- DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Attachment:
signature.asc
Description: PGP signature