* Re: [PATCH net-next v8 4/7] net: bcmgenet: add XDP_TX support
[not found] ` <20260429211702.42E86C2BCB4@smtp.kernel.org>
@ 2026-04-29 22:28 ` Nicolai Buchwitz
0 siblings, 0 replies; only message in thread
From: Nicolai Buchwitz @ 2026-04-29 22:28 UTC (permalink / raw)
To: sashiko; +Cc: bpf
On 29.4.2026 23:17, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 4 potential
> issue(s) to consider:
> - [High] Out-of-bounds array access in `bcmgenet_tx_reclaim` during
> interface teardown
> - [High] Incorrect DMA address calculation for local XDP_TX causes
> information leak and packet corruption
> - [High] Prepending `status_64` block overwrites XDP metadata and
> causes memory corruption
> - [Medium] XDP TX ring size is smaller than standard NAPI budget
> --
>
> commit 9add891fa4e7cf62ec26683116338b5877c21662
> Author: Nicolai Buchwitz <nb@tipi-net.de>
>
> net: bcmgenet: add XDP_TX support
>
> Implement XDP_TX using ring 16 (DESC_INDEX), the hardware default
> descriptor ring, dedicated to XDP TX for isolation from SKB TX queues.
>
>> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
>> b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
>> index 1b60571446e1..3c3b0c44ea8a 100644
>> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
>> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
>> @@ -48,8 +48,10 @@
>>
>> #define GENET_Q0_RX_BD_CNT \
>> (TOTAL_DESC - priv->hw_params->rx_queues *
>> priv->hw_params->rx_bds_per_q)
>> +#define GENET_Q16_TX_BD_CNT 32
>
> Is it possible to drop packets here during bursts since this TX ring is
> smaller
> than the standard NAPI budget?
Yes, by design. If the ring fills, frames are dropped, which is standard
XDP backpressure. Same approach as bnxt, mvneta, and other drivers.
>
> The standard RX NAPI budget is 64, and TX completions are reclaimed
> only once
> before the RX loop. If the RX loop processes a full budget of 64
> packets and
> they all result in an XDP_TX action, the first 32 will fill the TX
> ring.
>
> The remaining 32 packets would fail in bcmgenet_xdp_xmit_frame()
> because
> ring->free_bds < 1, and be dropped.
>
> [ ... ]
>> @@ -2043,6 +2069,9 @@ static void bcmgenet_tx_reclaim_all(struct
>> net_device *dev)
>> do {
>> bcmgenet_tx_reclaim(dev, &priv->tx_rings[i++], true);
>> } while (i <= priv->hw_params->tx_queues &&
>> netif_is_multiqueue(dev));
>> +
>> + /* Also reclaim XDP TX ring */
>> + bcmgenet_tx_reclaim(dev, &priv->xdp_tx_ring, true);
>> }
>
> Can this cause an out-of-bounds array access during interface teardown?
>
> When bcmgenet_tx_reclaim_all() calls bcmgenet_tx_reclaim() with all ==
> true,
> it unconditionally calls netdev_tx_reset_queue(netdev_get_tx_queue(dev,
> ring->index)).
bcmgenet_tx_reclaim() does not call netdev_tx_reset_queue() or
netdev_get_tx_queue(). The only netdev_get_tx_queue() in the reclaim
path (in __bcmgenet_tx_reclaim, for BQL) is guarded by
"if (ring->index != DESC_INDEX)". The netdev_tx_reset_queue() loop in
bcmgenet_fini_dma() iterates indices 0..tx_queues only.
>
> The XDP TX ring has an index of 16 (DESC_INDEX), but the network device
> is
> allocated with only GENET_MAX_MQ_CNT + 1 TX queues (typically 5).
> Accessing
> index 16 of dev->_tx is out-of-bounds, and netdev_tx_reset_queue() will
> write
> to this invalid memory.
>
> [ ... ]
>> @@ -2299,11 +2328,96 @@ static struct sk_buff
>> *bcmgenet_xdp_build_skb(struct bcmgenet_rx_ring *ring,
>> return skb;
>> }
>>
>> +static bool bcmgenet_xdp_xmit_frame(struct bcmgenet_priv *priv,
>> + struct xdp_frame *xdpf, bool dma_map)
>> +{
> [ ... ]
>> + if (dma_map) {
> [ ... ]
>> + } else {
>> + struct page *page = virt_to_page(xdpf->data);
>> +
>> + /* For local XDP_TX the caller already prepended the TSB
>> + * into xdpf->data/len, so dma_len == xdpf->len.
>> + */
>> + dma_len = xdpf->len;
>> + mapping = page_pool_get_dma_addr(page) +
>> + sizeof(*xdpf) + xdpf->headroom;
>
> Does this calculation result in an incorrect DMA address?
>
> The calculation implicitly assumes that xdpf resides exactly at the
> beginning
> of the page. However, the driver configures the RX page pool with
> offset = XDP_PACKET_HEADROOM (typically 256 bytes).
>
> By omitting the distance from the start of the page to xdpf, the
> calculated
> DMA address points XDP_PACKET_HEADROOM bytes before the actual packet
> data,
> which could lead to transmitting uninitialized memory.
Correct, xdpf does reside at the start of the page.
xdp_convert_buff_to_frame()
stores the xdp_frame at xdp->data_hard_start, which equals
page_address(page)
for our page_pool layout. page_pool_get_dma_addr() returns the DMA
address
of the page start (not offset by .offset). sizeof(*xdpf) +
xdpf->headroom
equals xdpf->data - data_hard_start, pointing to the prepended TSB.
>
>> + dma_sync_single_for_device(kdev, mapping, dma_len,
>> + DMA_BIDIRECTIONAL);
>> + }
> [ ... ]
>> + case XDP_TX:
>> + /* Prepend a zeroed TSB (Transmit Status Block). The GENET
>> + * MAC has TBUF_64B_EN set globally, so hardware expects every
>> + * TX buffer to begin with a 64-byte struct status_64. Back
>> + * up xdp->data into the RSB area (which is no longer needed
>> + * after the BPF program ran) and zero it.
>> + */
>> + if (xdp->data - xdp->data_hard_start <
>> + sizeof(struct status_64) + sizeof(struct xdp_frame)) {
>> + page_pool_put_full_page(ring->page_pool, rx_page,
>> + true);
>> + return XDP_DROP;
>> + }
>> + xdp->data -= sizeof(struct status_64);
>> + xdp->data_meta -= sizeof(struct status_64);
>> + memset(xdp->data, 0, sizeof(struct status_64));
>
> Could this overwrite XDP metadata and cause memory corruption?
xdp_convert_buff_to_frame() validates (headroom - metasize) >=
sizeof(struct xdp_frame) and returns NULL otherwise; we drop the frame
in that case. The memset writes to [xdp->data - 64, xdp->data] before
the data shift, which was previously the RSB area, not the metadata
area. Both data and data_meta are shifted equally, preserving the
metasize gap.
>
> The space check does not account for metasize (xdp->data -
> xdp->data_meta).
> If the BPF program appended metadata, the memset() here completely
> overwrites
> it.
>
> Furthermore, if metasize is > 0, the shifted xdp->data_meta pointer
> could
> underflow and point exactly to or before xdp->data_hard_start. When
> xdp_convert_buff_to_frame() is subsequently called, it writes the
> xdp_frame
> structure at data_hard_start, which would overlap with the shifted
> data_meta.
Thanks
Nicolai
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-04-29 22:28 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260428205846.2625550-5-nb@tipi-net.de>
[not found] ` <20260429211702.42E86C2BCB4@smtp.kernel.org>
2026-04-29 22:28 ` [PATCH net-next v8 4/7] net: bcmgenet: add XDP_TX support Nicolai Buchwitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox