]> www.infradead.org Git - users/willy/pagecache.git/commitdiff
net: renesas: rswitch: fix possible early skb release
authorNikita Yushchenko <nikita.yoush@cogentembedded.com>
Sun, 8 Dec 2024 09:50:01 +0000 (14:50 +0500)
committerJakub Kicinski <kuba@kernel.org>
Wed, 11 Dec 2024 03:02:47 +0000 (19:02 -0800)
When sending frame split into multiple descriptors, hardware processes
descriptors one by one, including writing back DT values. The first
descriptor could be already marked as completed when processing of
next descriptors for the same frame is still in progress.

Although only the last descriptor is configured to generate interrupt,
completion of the first descriptor could be noticed by the driver when
handling interrupt for the previous frame.

Currently, driver stores skb in the entry that corresponds to the first
descriptor. This results into skb could be unmapped and freed when
hardware did not complete the send yet. This opens a window for
corrupting the data being sent.

Fix this by saving skb in the entry that corresponds to the last
descriptor used to send the frame.

Fixes: d2c96b9d5f83 ("net: rswitch: Add jumbo frames handling for TX")
Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Link: https://patch.msgid.link/20241208095004.69468-2-nikita.yoush@cogentembedded.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/renesas/rswitch.c

index 8d18dae4d8fbfc69bce4a0fe64f296429f29b29c..f4fc2e7212c3c35906b6691c4f0550a8433c6c0e 100644 (file)
@@ -1681,8 +1681,9 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd
        if (dma_mapping_error(ndev->dev.parent, dma_addr_orig))
                goto err_kfree;
 
-       gq->skbs[gq->cur] = skb;
-       gq->unmap_addrs[gq->cur] = dma_addr_orig;
+       /* Stored the skb at the last descriptor to avoid skb free before hardware completes send */
+       gq->skbs[(gq->cur + nr_desc - 1) % gq->ring_size] = skb;
+       gq->unmap_addrs[(gq->cur + nr_desc - 1) % gq->ring_size] = dma_addr_orig;
 
        /* DT_FSTART should be set at last. So, this is reverse order. */
        for (i = nr_desc; i-- > 0; ) {