dmaengine: xilinx: avoid memory corruption for device_prep_dma_memcpy()
authorAkinobu Mita <akinobu.mita@gmail.com>
Mon, 13 Mar 2017 15:59:12 +0000 (00:59 +0900)
committerVinod Koul <vinod.koul@intel.com>
Tue, 14 Mar 2017 10:44:29 +0000 (16:14 +0530)
The device_prep_dma_memcpy() callback for this driver allocates a new
xilinx_dma_tx_descriptor whose TX segments list is initialized as empty,
but then gets invalid TX segment pointer by list_last_entry() from the
empty TX segments list and memory corruption happens by the attempt to
update the next descriptor in invalid TX segment pointer.

This removes unnecessary memory access for nonexistent tail TX segment
which causes memory corruption.

Cc: Vinod Koul <vinod.koul@intel.com>
Cc: Kedareswara rao Appana <appana.durga.rao@xilinx.com>
Cc: Michal Simek <monstr@monstr.eu>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
drivers/dma/xilinx/xilinx_dma.c

index df1676e..8cf87b1 100644 (file)
@@ -1661,7 +1661,7 @@ xilinx_cdma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst,
 {
        struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
        struct xilinx_dma_tx_descriptor *desc;
-       struct xilinx_cdma_tx_segment *segment, *prev;
+       struct xilinx_cdma_tx_segment *segment;
        struct xilinx_cdma_desc_hw *hw;
 
        if (!len || len > XILINX_DMA_MAX_TRANS_LEN)
@@ -1688,21 +1688,11 @@ xilinx_cdma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst,
                hw->dest_addr_msb = upper_32_bits(dma_dst);
        }
 
-       /* Fill the previous next descriptor with current */
-       prev = list_last_entry(&desc->segments,
-                              struct xilinx_cdma_tx_segment, node);
-       prev->hw.next_desc = segment->phys;
-
        /* Insert the segment into the descriptor segments list. */
        list_add_tail(&segment->node, &desc->segments);
 
-       prev = segment;
-
-       /* Link the last hardware descriptor with the first. */
-       segment = list_first_entry(&desc->segments,
-                               struct xilinx_cdma_tx_segment, node);
        desc->async_tx.phys = segment->phys;
-       prev->hw.next_desc = segment->phys;
+       hw->next_desc = segment->phys;
 
        return &desc->async_tx;