mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Nicolai Buchwitz <nb@tipi-net.de>
To: netdev-bot+sashiko@kernel.org
Cc: opendmb@gmail.com, florian.fainelli@broadcom.com,
	bcm-kernel-feedback-list@broadcom.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@kernel.org, kuba@kernel.org,
	pabeni@redhat.com, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, dave.stevenson@raspberrypi.com,
	justin.chen@broadcom.com, pierremarinleclercq88@gmail.com
Subject: Re: [PATCH net-next v2 7/7] net: bcmgenet: reassemble jumbo frames from status block fragments
Date: Wed, 07 Oct 2026 09:16:15 +0200	[thread overview]
Message-ID: <6bfa3380b5f5b91ae5bc8b37b22bdb85@tipi-net.de> (raw)
In-Reply-To: <179132614439.434549.8289444609097315292@kernel.org>

Dear Clashiko

On 7.10.2026 00:35, netdev-bot+sashiko@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 4 potential
> issue(s) to consider.
> 
> Critical: 0 · High: 1 · Medium: 2 · Low: 1
> 
> If you believe none of the issues are legitimate, please reply to each
> issue of Medium severity or higher and explain why the AI is wrong.
> If any of them are legitimate and you plan to respin, please let 
> patchwork
> know by including "pw-bot: cr" as a separate line at the end of your 
> reply
> (one such reply per series is enough).
> 
> - [High] Use-after-free read of the last status block in
>   bcmgenet_desc_rx() when CRC forwarding is on.
> - [Medium] TX descriptor length can overflow the 12-bit length field 
> once
>   the MTU goes past about 4 KB.
> - [Medium] Short SOP descriptor followed by continuation fragments can
>   reach BUG() in eth_type_trans().
> - [Low] The comment on bcmgenet_pkt_rdy_thld() is now stale.
> 
> --
> 
> net: bcmgenet: reassemble jumbo frames from status block fragments
> 
> The hardware splits a frame longer than the packet ready threshold 
> across
> several descriptors, each with its own status block. This patch 
> reassembles
> those descriptors into one skb by attaching the later ones as page 
> frags.
> It also raises max_mtu on v2+ to ENET_MAX_JUMBO_MTU, which is derived 
> from
> the 14-bit UMAC_MAX_FRAME_LEN.
> 
>> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
>> b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
>> index e8f86374c7cd8..faa13f12ce7e6 100644
>> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
>> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
>> @@ -84,11 +84,8 @@
>>  				      ENET_THLD_MAX * ENET_THLD_UNIT, \
>>  				      ENET_THLD_PAGE_LEN)
>> 
>> -/* Largest MTU that fits one descriptor, with room for a VLAN tag so 
>> a VLAN
>> - * interface can use the parent MTU.
>> - */
>> -#define ENET_MAX_MTU		(ENET_THLD_MAX_LEN - GENET_RBUF_ALIGN - \
>> -				 ETH_HLEN - VLAN_HLEN)
>> +/* UMAC_MAX_FRAME_LEN is 14 bits wide and counts the FCS */
>> +#define ENET_MAX_JUMBO_MTU	(GENMASK(13, 0) - ENET_FRAME_OVERHEAD)
> 
> [Severity: Medium]
> This limit comes from the UMAC frame length only. Once bcmgenet_probe()
> sets max_mtu to it, the TX path can see MTUs up to 16347. Can the TX
> descriptor length field hold buffers that large?
> 
> bcmgenet_xmit() still maps the linear head and each page frag as a 
> single
> descriptor. It writes the size into len_stat with no mask, cap or 
> split:
> 
> bcmgenet_xmit() {
>     ...
> 		len_stat = (size << DMA_BUFLENGTH_SHIFT) |
> 			   (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT);
>     ...
> }
> 
> The only in-tree description of that field says it is 12 bits wide:
> 
> bcmgenet.h:
> /* Tx/Rx Dma Descriptor common bits*/
> #define DMA_BUFLENGTH_MASK		0x0fff
> #define DMA_BUFLENGTH_SHIFT		16
> 
> At jumbo MTU, skb_headlen() can approach 16 KB, plus the 64-byte TSB 
> that
> bcmgenet_add_tsb() adds. TCP frags of around 9 KB are also common.
> 
> If the field really is 12 bits, would the length wrap modulo 4096, with 
> the
> upper bits spilling into bits 31:28? Would that truncate or corrupt the
> frame on the wire? Before this patch the largest TX buffer was about 
> 3.9 KB.
> 
> Separately, bcmgenet_init_tx_ring() still sets DMA_RING_BUF_SIZE from
> priv->rx_buf_len, which is at most about 3.9 KB:
> 
> bcmgenet_init_tx_ring() {
>     ...
> 	bcmgenet_tdma_ring_writel(priv, index,
> 				  ((size << DMA_RING_SIZE_SHIFT) |
> 				   priv->rx_buf_len), DMA_RING_BUF_SIZE);
>     ...
> }
> 
> Is that setting still valid now that one TX descriptor can be several 
> times
> larger? Could the commit message say whether the TX descriptor length 
> and
> the TX buffer size limits allow more than 4095 bytes?

Not 12 bits, see v1. Frames up to 8998 bytes in one descriptor went
out intact. Will add a note in the commit message...

> 
> [ ... ]
> 
>> @@ -2333,6 +2330,54 @@ static int bcmgenet_rx_refill(struct 
>> bcmgenet_rx_ring *ring,
>>  	return 0;
>>  }
>> 
> 
> [ ... ]
> 
>> +/* A frame longer than the threshold arrives in several descriptors, 
>> each with
>> + * its own status block. Only the first one carries a header, so hand 
>> the page
>> + * of every later one to the frame already being collected. Returns 
>> the frame
>> + * once EOP is in, NULL while more descriptors are expected or once 
>> the frame
>> + * had to be dropped.
>> + */
> 
> [Severity: Low]
> This isn't a bug, but the comment above bcmgenet_pkt_rdy_thld() now 
> looks
> stale:
> 
> /* Receive threshold in register units. Covers the alignment bytes and 
> the
>  * frame, but not the status block, which the hardware adds on top.
>  */
> 
> With max_mtu raised to ENET_MAX_JUMBO_MTU, any MTU above about 3.5-3.8 
> KB
> is clamped to ENET_THLD_MAX_LEN / ENET_THLD_UNIT. The threshold then no
> longer covers the frame, which contradicts the comment here. Should 
> that
> comment be updated?

Ack.

> 
> [ ... ]
> 
>> @@ -2490,8 +2556,18 @@ static unsigned int bcmgenet_desc_rx(struct 
>> bcmgenet_rx_ring *ring,
>>  		skb_reserve(skb, GENET_RSB_PAD);
>>  		__skb_put(skb, len - GENET_RSB_PAD);
>> 
>> -		if (priv->crc_fwd_en) {
>> -			skb_trim(skb, skb->len - ETH_FCS_LEN);
>> +		if (unlikely(!(dma_flag & DMA_EOP))) {
>> +			ring->frag_head = skb;
>> +			goto next;
>> +		}
> 
> [Severity: Medium]
> Could a short SOP head lead to BUG() in eth_type_trans()?
> 
> For an SOP descriptor the only length check is len >= GENET_RSB_PAD 
> (66). A
> descriptor with SOP and no EOP that carries fewer than ETH_HLEN frame 
> bytes
> would still become ring->frag_head. Later descriptors are then added as
> frags.
> 
> Nothing calls pskb_may_pull() before this line after deliver:
> 
> 		skb->protocol = eth_type_trans(skb, priv->dev);
> 
> If the linear part has fewer than 14 bytes and frags are present,
> __skb_pull() would see skb->len < skb->data_len and call BUG().
> 
> bcmgenet_pkt_rdy_thld() keeps the threshold at ENET_THLD_DEFAULT (2048
> bytes) or more. Correct hardware should therefore always fill an SOP
> descriptor without EOP to around 2 KB. Reaching this would take a
> malformed status block from the MAC, so this is hardening rather than a
> path reachable from the network.
> 
> Would it be worth checking that an SOP descriptor without EOP holds at
> least ETH_HLEN frame bytes?

AFAIU the MAC never does that, but as it is one compare, I can add it...

> 
>> +
>> +deliver:
>> +
>> +		if (priv->crc_fwd_en &&
>> +		    unlikely(pskb_trim(skb, skb->len - ETH_FCS_LEN))) {
>> +			BCMGENET_STATS64_INC(stats, dropped);
>> +			dev_kfree_skb_any(skb);
>> +			goto next;
>>  		}
>> 
>>  		/* Set up checksum offload */
> 
> [Severity: High]
> Can this read the status block from a page that has already been freed?
> 
> For a reassembled frame, status still points to page_address(rx_page) +
> rx_offset of the EOP descriptor. bcmgenet_add_frag() has already given 
> that
> page to the skb as its last frag.
> 
> When crc_fwd_en is set, pskb_trim() on this non-linear skb goes through
> ___pskb_trim(). That can release the page in two ways.
> 
> First, if the EOP descriptor carries 4 or fewer frame bytes, the last 
> frag
> is released with skb_frag_unref(). A non-SOP len of 64-68 passes the
> min_len check.
> 
> Second, skb->sk is NULL, so skb_condense() runs. It may pull the 
> remaining
> frag data into the head and free every frag.
> 
> The page then goes back through napi_pp_put_page(). If it cannot be
> recycled (pfmemalloc, remote NUMA node, or full cache and ring), it can 
> be
> returned to the page allocator via page_pool_return_netmem().
> 
> The very next statements read the status block:
> 
> 		/* Set up checksum offload */
> 		if (dev->features & NETIF_F_RXCSUM) {
> 			rx_csum = (__force __be16)(status->rx_csum & 0xffff);
> 
> The value read there is then used as CHECKSUM_COMPLETE. Before this 
> patch
> the skb was always linear and status pointed into the head buffer, 
> which
> skb_trim() never frees.
> 
> Should rx_csum be read before pskb_trim() is called?

Yes, will fix it.

---
pw-bot: cr

      reply	other threads:[~2026-10-07  7:16 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-05 22:24 [PATCH net-next v2 0/7] net: bcmgenet: support larger MTUs Nicolai Buchwitz
2026-10-05 22:24 ` [PATCH net-next v2 1/7] net: bcmgenet: let the caller decide whether to start the PHY Nicolai Buchwitz
2026-10-05 22:24 ` [PATCH net-next v2 2/7] net: bcmgenet: allow a continuation descriptor without the alignment pad Nicolai Buchwitz
2026-10-05 23:05   ` Florian Fainelli
2026-10-05 22:24 ` [PATCH net-next v2 3/7] net: bcmgenet: rename ENET_MAX_MTU_SIZE to ENET_MAX_FRAME_LEN Nicolai Buchwitz
2026-10-05 23:06   ` Florian Fainelli
2026-10-05 22:24 ` [PATCH net-next v2 4/7] net: bcmgenet: derive the receive buffer length from the MTU Nicolai Buchwitz
2026-10-05 23:11   ` Florian Fainelli
2026-10-06 22:35   ` netdev-bot+sashiko
2026-10-05 22:24 ` [PATCH net-next v2 5/7] net: bcmgenet: allow the MTU to be changed Nicolai Buchwitz
2026-10-05 22:24 ` [PATCH net-next v2 6/7] net: bcmgenet: pad transmit frames out of the packet ready window Nicolai Buchwitz
2026-10-06 22:35   ` netdev-bot+sashiko
2026-10-07  7:11     ` Nicolai Buchwitz
2026-10-05 22:24 ` [PATCH net-next v2 7/7] net: bcmgenet: reassemble jumbo frames from status block fragments Nicolai Buchwitz
2026-10-06 22:35   ` netdev-bot+sashiko
2026-10-07  7:16     ` Nicolai Buchwitz [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6bfa3380b5f5b91ae5bc8b37b22bdb85@tipi-net.de \
    --to=nb@tipi-net.de \
    --cc=andrew+netdev@lunn.ch \
    --cc=bcm-kernel-feedback-list@broadcom.com \
    --cc=dave.stevenson@raspberrypi.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@kernel.org \
    --cc=florian.fainelli@broadcom.com \
    --cc=justin.chen@broadcom.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev-bot+sashiko@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=opendmb@gmail.com \
    --cc=pabeni@redhat.com \
    --cc=pierremarinleclercq88@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®