Netdev List
 help / color / mirror / Atom feed
From: "Théo Lebrun" <theo.lebrun@bootlin.com>
To: "Paolo Abeni" <pabeni@redhat.com>
Cc: <conor.dooley@microchip.com>, <andrew+netdev@lunn.ch>,
	<davem@davemloft.net>, <edumazet@google.com>, <kuba@kernel.org>,
	<richardcochran@gmail.com>, <linux@armlinux.org.uk>,
	<netdev@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<nicolas.ferre@microchip.com>, <claudiu.beznea@tuxon.dev>,
	<pvalerio@redhat.com>, <nb@tipi-net.de>,
	<vladimir.kondratiev@mobileye.com>, <gregory.clement@bootlin.com>,
	<benoit.monin@bootlin.com>, <tawfik.bayouk@mobileye.com>,
	<thomas.petazzoni@bootlin.com>, <maxime.chevallier@bootlin.com>
Subject: Re: [PATCH net-next v3 07/15] net: macb: introduce macb_context struct for buffer management
Date: Mon, 13 Jul 2026 14:53:55 +0200	[thread overview]
Message-ID: <DJXGIM9EGPT8.4UHNYP2Y0GOP@bootlin.com> (raw)
In-Reply-To: <20260708102716.169767-1-pabeni@redhat.com>

Hello Paolo's LLM,

On Wed Jul 8, 2026 at 12:27 PM CEST, Paolo Abeni wrote:
> From: AI Reviewer <ai@example.com>
>
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> Full review at: https://netdev-ai.bots.linux.dev/sashiko/
> ---
> net: macb: introduce macb_context struct for buffer management
>
> This patch moves per-queue ring buffers and ring-size parameters out of
> struct macb / struct macb_queue into a new struct macb_context that is
> allocated on open and freed on close, so future patches can swap in a
> new context while the interface is running.
>
>> diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
>> index 951a7f080225..dfb1d49d841c 100644
>> --- a/drivers/net/ethernet/cadence/macb_main.c
>> +++ b/drivers/net/ethernet/cadence/macb_main.c
>
> [ ... ]
>
>> @@ -1257,6 +1288,7 @@ static void macb_tx_error_task(struct work_struct *work)
>>  	struct macb_queue *queue = container_of(work, struct macb_queue,
>>  						tx_error_task);
>>  	unsigned int q = queue - queue->bp->queues;
>> +	struct macb_txq *txq = macb_txq(queue);
>>  	struct macb *bp = queue->bp;
>
> [High]
> Can macb_tx_error_task() dereference a freed context?
>
> macb_tx_error_task is scheduled from macb_interrupt():
>
>     schedule_work(&queue->tx_error_task);
>
> After this patch, the very first thing the worker does is:
>
>     struct macb_txq *txq = macb_txq(queue);
>
> which expands to &bp->ctx->txq[q] and dereferences bp->ctx.
>
> Looking at macb_close():
>
>     macb_reset_hw(bp);
>     ...
>     macb_free(bp);
>     kfree(bp->ctx);
>     bp->ctx = NULL;
>
> There is no cancel_work_sync(&queue->tx_error_task), and macb_reset_hw()
> does not drain the workqueue. If an interrupt scheduled the work just
> before close, or the work was already pending, the worker can run after
> kfree(bp->ctx) and hit a NULL dereference (and a use-after-free if
> macb_open() re-allocates ctx concurrently via ethtool ring reconfig).
>
> The same reasoning applies to bp->hresp_err_bh_work, which is queued
> from macb_interrupt() and whose handler calls
> mog_init_rings()/macb_init_buffers() that read bp->ctx->tx_ring_size and
> bp->ctx->{tx,rx}q[q]. cancel_work_sync(&bp->hresp_err_bh_work) is only
> called from macb_remove(), not macb_close().

All of this is a valid concern.

> Pre-patch these fields lived inside the embedded struct macb_queue so a
> late worker would touch stale-but-addressable memory; post-patch the
> first indirection through bp->ctx faults.

This pre-series analysis is wrong however. Current upstream would crash:
macb_tx_error_task() restarts the HW and it even assigns
queue->tx_ring_dma which still contains the freed DMA address
(macb_free()/macb_close() don't reset that value).

Summary: this patch turns potential memory corruption into a NULL
pointer dereference.

> Would adding cancel_work_sync(&queue->tx_error_task) per queue and
> cancel_work_sync(&bp->hresp_err_bh_work) before kfree(bp->ctx) in
> macb_close() close this window?

Yes that is the way forward. It will probably be separate and target
net/main. Not specifically because I want it backported (it'd be nice
but issue is super unlikely and no one reported it) but mostly because
this series is already 15 patches long.

>> @@ -3690,8 +3778,8 @@ static int macb_set_ringparam(struct net_device *netdev,
>>  		macb_close(bp->netdev);
>>  	}
>>  
>> -	bp->rx_ring_size = new_rx_size;
>> -	bp->tx_ring_size = new_tx_size;
>> +	bp->configured_rx_ring_size = new_rx_size;
>> +	bp->configured_tx_ring_size = new_tx_size;
>>  
>>  	if (reset)
>>  		macb_open(bp->netdev);
>
> [Medium]
> Should the return value of macb_open() be checked here?
>
> This patch adds a new failure point inside macb_open():
>
>     bp->ctx = kzalloc_obj(*bp->ctx);
>     if (!bp->ctx) {
>         err = -ENOMEM;
>         goto pm_exit;
>     }
>
> On failure, bp->ctx remains NULL and the interface stays down, but
> macb_set_ringparam() ignores the return value and reports success to
> userspace. The commit message says the motivation is to improve
> reliability under memory pressure, but this caller silently swallows the
> new allocation failure.

No need, this series ends with context swapping and the
macb_context_swap_end() operation, which replaces the macb_open()
highlighted here, cannot fail.

>> @@ -5039,6 +5125,12 @@ static int at91ether_open(struct net_device *netdev)
>>  	if (ret < 0)
>>  		return ret;
>>  
>> +	bp->ctx = kzalloc_obj(*bp->ctx);
>> +	if (!bp->ctx) {
>> +		ret = -ENOMEM;
>> +		goto pm_exit;
>> +	}
>> +
>>  	/* Clear internal statistics */
>>  	ctl = macb_readl(bp, NCR);
>>  	macb_writel(bp, NCR, ctl | MACB_BIT(CLRSTAT));
>
> [Low]
> Should bp->ctx->rx_ring_size, tx_ring_size and rx_buffer_size be
> initialized on this path?
>
> macb_open() sets them from configured_{rx,tx}_ring_size and calls
> macb_init_rx_buffer_size(), but at91ether_open() leaves them at zero
> after kzalloc_obj().
>
> Helpers such as macb_rx_ring_wrap() compute:
>
>     return index & (bp->ctx->rx_ring_size - 1);
>
> which becomes index & 0xFFFFFFFF when rx_ring_size is 0. It happens to
> be harmless today because the at91ether path constrains indices to
> [0, AT91ETHER_MAX_RX_DESCR-1] independently and macb_get_regs() reports
> zeroed head/tail for the tx-less at91ether, but pre-patch macb_init_dflt()
> unconditionally set bp->rx_ring_size = DEFAULT_RX_RING_SIZE.
>
> Any future shared helper that used tx_ring_size as a stride or divisor
> would misbehave on at91ether.

Yes. Null impact (but it would be better in theory).

>> @@ -5076,6 +5171,9 @@ static int at91ether_close(struct net_device *netdev)
>>  
>>  	at91ether_stop(bp);
>>  
>> +	kfree(bp->ctx);
>> +	bp->ctx = NULL;
>> +
>>  	pm_runtime_put(&bp->pdev->dev);
>>  
>>  	return 0;
>
> [High]
> Is there IRQ synchronization missing before freeing bp->ctx on this
> path?
>
> at91ether_stop() disables MAC RX/TX and writes IDR to mask further
> interrupts, but does not synchronize with a handler already running or
> already dispatched on another CPU. at91ether_interrupt() calls
> at91ether_rx(), which after this patch does:
>
>     struct macb_rxq *rxq = &bp->ctx->rxq[0];
>     ...
>     desc = macb_rx_desc(queue, rxq->tail);
>     ...
>     p_recv = rxq->buffers + rxq->tail * AT91ETHER_MAX_RBUFF_SZ;
>
> If the handler is in flight when kfree(bp->ctx); bp->ctx = NULL runs,
> the next access through bp->ctx faults. The macb_open()/macb_close()
> path is somewhat protected by napi_disable() before macb_free(), but
> at91ether does not use NAPI and has no equivalent barrier.
>
> Would a synchronize_irq(bp->netdev->irq) between at91ether_stop() and
> kfree(bp->ctx) close this?

Ah at91ether_interrupt() doesn't grab bp->lock as macb_interrupt() does.
Indeed synchronize_irq() would solve this.

Thanks,

--
Théo Lebrun, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


  reply	other threads:[~2026-07-13 12:54 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-01 15:59 [PATCH net-next v3 00/15] net: macb: implement context swapping Théo Lebrun
2026-07-01 15:59 ` [PATCH net-next v3 01/15] net: macb: drop "consistent" from alloc/free function names Théo Lebrun
2026-07-02 10:41   ` Nicolai Buchwitz
2026-07-03 11:28   ` Conor Dooley
2026-07-03 16:32     ` Théo Lebrun
2026-07-03 16:34       ` Conor Dooley
2026-07-01 15:59 ` [PATCH net-next v3 02/15] net: macb: unify device pointer naming convention Théo Lebrun
2026-07-03 11:29   ` Conor Dooley
2026-07-01 15:59 ` [PATCH net-next v3 03/15] net: macb: unify variable naming convention in at91ether functions Théo Lebrun
2026-07-02 10:42   ` Nicolai Buchwitz
2026-07-03 11:30   ` Conor Dooley
2026-07-01 15:59 ` [PATCH net-next v3 04/15] net: macb: unify queue index variable naming convention and types Théo Lebrun
2026-07-02 10:43   ` Nicolai Buchwitz
2026-07-03 11:34   ` Conor Dooley
2026-07-03 17:10     ` Théo Lebrun
2026-07-01 15:59 ` [PATCH net-next v3 05/15] net: macb: enforce reverse christmas tree (RCT) convention Théo Lebrun
2026-07-02 10:48   ` Nicolai Buchwitz
2026-07-03 11:35   ` Conor Dooley
2026-07-01 15:59 ` [PATCH net-next v3 06/15] net: macb: allocate tieoff descriptor once across device lifetime Théo Lebrun
2026-07-02 10:54   ` Nicolai Buchwitz
2026-07-13 12:00     ` Théo Lebrun
2026-07-01 15:59 ` [PATCH net-next v3 07/15] net: macb: introduce macb_context struct for buffer management Théo Lebrun
2026-07-03 11:39   ` Conor Dooley
2026-07-08 10:27   ` Paolo Abeni
2026-07-13 12:53     ` Théo Lebrun [this message]
2026-07-01 15:59 ` [PATCH net-next v3 08/15] net: macb: avoid macb_init_rx_buffer_size() modifying state Théo Lebrun
2026-07-01 15:59 ` [PATCH net-next v3 09/15] net: macb: make `struct macb` subset reachable from macb_context struct Théo Lebrun
2026-07-01 15:59 ` [PATCH net-next v3 10/15] net: macb: change caps helpers signatures Théo Lebrun
2026-07-03 11:43   ` Conor Dooley
2026-07-01 15:59 ` [PATCH net-next v3 11/15] net: macb: change function signatures to take contexts Théo Lebrun
2026-07-03 11:45   ` Conor Dooley
2026-07-01 15:59 ` [PATCH net-next v3 12/15] net: macb: introduce macb_context_alloc() helper Théo Lebrun
2026-07-01 15:59 ` [PATCH net-next v3 13/15] net: macb: re-read ISR inside IRQ handler locked section Théo Lebrun
2026-07-03 12:09   ` Conor Dooley
2026-07-13 15:04     ` Théo Lebrun
2026-07-01 15:59 ` [PATCH net-next v3 14/15] net: macb: use context swapping in .set_ringparam() Théo Lebrun
2026-07-02 10:37   ` Nicolai Buchwitz
2026-07-13 16:41     ` Théo Lebrun
2026-07-01 15:59 ` [PATCH net-next v3 15/15] net: macb: use context swapping in .ndo_change_mtu() Théo Lebrun

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=DJXGIM9EGPT8.4UHNYP2Y0GOP@bootlin.com \
    --to=theo.lebrun@bootlin.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=benoit.monin@bootlin.com \
    --cc=claudiu.beznea@tuxon.dev \
    --cc=conor.dooley@microchip.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=gregory.clement@bootlin.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=maxime.chevallier@bootlin.com \
    --cc=nb@tipi-net.de \
    --cc=netdev@vger.kernel.org \
    --cc=nicolas.ferre@microchip.com \
    --cc=pabeni@redhat.com \
    --cc=pvalerio@redhat.com \
    --cc=richardcochran@gmail.com \
    --cc=tawfik.bayouk@mobileye.com \
    --cc=thomas.petazzoni@bootlin.com \
    --cc=vladimir.kondratiev@mobileye.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