diff mbox series

[1/5] net: renesas: rswitch: fix possible early skb release

Message ID 20241202134904.3882317-2-nikita.yoush@cogentembedded.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series net: renesas: rswitch: several fixes | expand

Checks

Context Check Description
netdev/series_format warning Target tree name not specified in the subject
netdev/tree_selection success Guessed tree name to be net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 3 this patch: 3
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 1 maintainers not CCed: andrew+netdev@lunn.ch
netdev/build_clang success Errors and warnings before: 3 this patch: 3
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 304 this patch: 304
netdev/checkpatch warning WARNING: line length of 100 exceeds 80 columns WARNING: line length of 81 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-12-02--15-00 (tests: 760)

Commit Message

Nikita Yushchenko Dec. 2, 2024, 1:49 p.m. UTC
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>
---
 drivers/net/ethernet/renesas/rswitch.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Jacob Keller Dec. 4, 2024, 12:22 a.m. UTC | #1
On 12/2/2024 5:49 AM, Nikita Yushchenko wrote:
> 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>
> ---
>  drivers/net/ethernet/renesas/rswitch.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c
> index b80aa27a7214..32b32aa7e01f 100644
> --- a/drivers/net/ethernet/renesas/rswitch.c
> +++ b/drivers/net/ethernet/renesas/rswitch.c
> @@ -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;
>  

nr_desc is non-zero, so if nr_desc was 1, then this would point to
gq->cur + 0 mod ring_size, i.e. gq->cur.

I might have possibly computed that separately as a local variable since
this expression is repeated twice, but I don't think thats going to do
too much for readability either way.

Ok

Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>

>  	/* DT_FSTART should be set at last. So, this is reverse order. */
>  	for (i = nr_desc; i-- > 0; ) {
diff mbox series

Patch

diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c
index b80aa27a7214..32b32aa7e01f 100644
--- a/drivers/net/ethernet/renesas/rswitch.c
+++ b/drivers/net/ethernet/renesas/rswitch.c
@@ -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; ) {