diff mbox series

[1/4] net: ll_temac: Make sure to free skb when it is completely used

Message ID d9200a5023973fbe372a2d51dc4e500400450ecd.1624013456.git.esben@geanix.com (mailing list archive)
State Accepted
Commit 6aa32217a9a446275440ee8724b1ecaf1838df47
Delegated to: Netdev Maintainers
Headers show
Series [1/4] net: ll_temac: Make sure to free skb when it is completely used | expand

Checks

Context Check Description
netdev/cover_letter warning Series does not have a cover letter
netdev/fixes_present success Link
netdev/patch_count success Link
netdev/tree_selection success Guessed tree name to be net-next
netdev/subject_prefix warning Target tree name not specified in the subject
netdev/cc_maintainers success CCed 10 of 10 maintainers
netdev/source_inline success Was 0 now: 0
netdev/verify_signedoff success Link
netdev/module_param success Was 0 now: 0
netdev/build_32bit success Errors and warnings before: 29 this patch: 29
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/verify_fixes success Link
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 18 lines checked
netdev/build_allmodconfig_warn success Errors and warnings before: 29 this patch: 29
netdev/header_inline success Link

Commit Message

Esben Haabendal June 18, 2021, 10:52 a.m. UTC
With the skb pointer piggy-backed on the TX BD, we have a simple and
efficient way to free the skb buffer when the frame has been transmitted.
But in order to avoid freeing the skb while there are still fragments from
the skb in use, we need to piggy-back on the TX BD of the skb, not the
first.

Without this, we are doing use-after-free on the DMA side, when the first
BD of a multi TX BD packet is seen as completed in xmit_done, and the
remaining BDs are still being processed.

Cc: stable@vger.kernel.org # v5.4+
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

Comments

patchwork-bot+netdevbpf@kernel.org June 18, 2021, 7:20 p.m. UTC | #1
Hello:

This series was applied to netdev/net.git (refs/heads/master):

On Fri, 18 Jun 2021 12:52:23 +0200 you wrote:
> With the skb pointer piggy-backed on the TX BD, we have a simple and
> efficient way to free the skb buffer when the frame has been transmitted.
> But in order to avoid freeing the skb while there are still fragments from
> the skb in use, we need to piggy-back on the TX BD of the skb, not the
> first.
> 
> Without this, we are doing use-after-free on the DMA side, when the first
> BD of a multi TX BD packet is seen as completed in xmit_done, and the
> remaining BDs are still being processed.
> 
> [...]

Here is the summary with links:
  - [1/4] net: ll_temac: Make sure to free skb when it is completely used
    https://git.kernel.org/netdev/net/c/6aa32217a9a4
  - [2/4] net: ll_temac: Add memory-barriers for TX BD access
    https://git.kernel.org/netdev/net/c/28d9fab458b1
  - [3/4] net: ll_temac: Fix TX BD buffer overwrite
    https://git.kernel.org/netdev/net/c/c364df2489b8
  - [4/4] net: ll_temac: Avoid ndo_start_xmit returning NETDEV_TX_BUSY
    https://git.kernel.org/netdev/net/c/f63963411942

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
diff mbox series

Patch

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index a1f5f07f4ca9..e82f162cd80c 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -876,7 +876,6 @@  temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		return NETDEV_TX_OK;
 	}
 	cur_p->phys = cpu_to_be32(skb_dma_addr);
-	ptr_to_txbd((void *)skb, cur_p);
 
 	for (ii = 0; ii < num_frag; ii++) {
 		if (++lp->tx_bd_tail >= lp->tx_bd_num)
@@ -915,6 +914,11 @@  temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	}
 	cur_p->app0 |= cpu_to_be32(STS_CTRL_APP0_EOP);
 
+	/* Mark last fragment with skb address, so it can be consumed
+	 * in temac_start_xmit_done()
+	 */
+	ptr_to_txbd((void *)skb, cur_p);
+
 	tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
 	lp->tx_bd_tail++;
 	if (lp->tx_bd_tail >= lp->tx_bd_num)