Netdev List
 help / color / mirror / Atom feed
From: mingming cao <mmc@linux.ibm.com>
To: netdev-bot+sashiko@kernel.org
Cc: netdev@vger.kernel.org, maddy@linux.ibm.com, mpe@ellerman.id.au,
	npiggin@gmail.com, chleroy@kernel.org, ritesh.list@gmail.com,
	sshegde@linux.ibm.com, nnac123@linux.ibm.com,
	andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@kernel.org,
	kuba@kernel.org, pabeni@redhat.com,
	linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
	horms@kernel.org, davemarq@linux.ibm.com, bjking1@linux.ibm.com,
	stephen@networkplumber.org
Subject: Re: [PATCH net-next v3 4/8] ibmveth: step past bad RX correlators instead of spinning or oopsing
Date: Sun, 11 Oct 2026 22:03:55 -0700	[thread overview]
Message-ID: <93cc87b4-14ce-43d9-a29e-d9a6795bb0d5@linux.ibm.com> (raw)
In-Reply-To: <179166081271.434549.2458181310224040226@kernel.org>


On 10/10/26 12:33 PM, netdev-bot+sashiko@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential
> issue(s) to consider.
>
> Critical: 0 · High: 3 (1) · Medium: 0 · Low: 0
>
> 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] This patch's short-frame check is incomplete.
> - [High] Returning budget - 1 does not make ibmveth_poll()'s schedule-
>    and-continue path safe when threaded NAPI and busy polling are both…
> - [High] net/ibmveth: TOCTOU double-fetch of RX correlator in
>    harvest_buffer
>
> Pre-existing issues:
> - [High] This problem wasn't introduced by this patch, but
>    ibmveth_rx_csum_helper() calls ip_fast_csum(iph, iph->ihl) whenever…
>
> --


Thank you for the review. I agree with all four High findings on this
patch.

I will address them in v4 on the same net-next base (d8674294aefe).
Patches 1-3 and 5-8 are unchanged from v3. Patch 4 fixes the poll
tail (no restart_poll after napi_complete_done; mask then queue the
NAPI), passes the correlator poll already read into harvest, and
keeps the buffer-bound and ETH_HLEN drops without claiming they cover
the RX offload helpers.

The helper header checks (short frames, ihl,
doff, fragments, and the ip_fast_csum() case) are split into a new
patch 9 at the end of the series, with their own Fixes: tags and KUnit
cases.

I will post v4 on netdev shortly.
v4 was tested with KUnit on qemu pseries and on a POWER10 LPAR (the v3
suite plus large-send iperf3 over IPv4/IPv6 at MTU 1500 and 9000).

Thanks,
Mingming

pw-bot: cr

> ibmveth: step past bad RX correlators instead of spinning or oopsing
>
> This patch makes ibmveth_poll() advance the RX ring past slots with a bad
> correlator, including correlators that name an inactive pool, instead of
> breaking out and restarting on the same slot. It counts those slots as
> drops and schedules a reset. It also drops frames that do not fit the pool
> buffer or are shorter than an Ethernet header, and returns budget - 1 once
> napi_schedule() has queued the NAPI.
>
>> diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
>> index cee0e9783b2ab..55c0b5d6e0a9f 100644
>> --- a/drivers/net/ethernet/ibm/ibmveth.c
>> +++ b/drivers/net/ethernet/ibm/ibmveth.c
> [ ... ]
>
>> @@ -1481,19 +1525,46 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
> [ ... ]
>
>>   		} else {
>>   			struct sk_buff *skb, *new_skb;
>>   			int length = ibmveth_rxq_frame_length(adapter);
>>   			int offset = ibmveth_rxq_frame_offset(adapter);
>>   			int csum_good = ibmveth_rxq_csum_good(adapter);
>>   			int lrg_pkt = ibmveth_rxq_large_packet(adapter);
>> +			u64 correlator = ibmveth_rxq_correlator(adapter);
>> +			unsigned int pool, room, off, len;
>>   			__sum16 iph_check = 0;
> [Severity: High]
> The commit message says the bound uses the pool "from the correlator
> that was validated, read once, not from a second read of the ring".
> Doesn't ibmveth_rxq_harvest_buffer() still do that second read?
>
> ibmveth_poll() now reads the correlator once with
> ibmveth_rxq_correlator(). It uses that value to look up skb in
> ibmveth_rxq_get_buffer() and to compute room. Every harvest after that
> ignores it, though: this call, the copybreak call and the one on the
> bad-frame path. ibmveth_rxq_harvest_buffer() loads
> queue_addr[rx_queue.index].correlator again with a plain load and
> passes that to ibmveth_remove_buffer_from_pool(). Nothing ties the
> second value to the one poll validated.
>
> Suppose the entry changes between the two loads, so skb is looked up
> from slot A and harvested from slot B. On this reuse=false path:
>
> - rx_buff_pool[].skbuff[B] is cleared and dma_addr[B] is unmapped.
>    B goes on free_map, and the skb that was in slot B is leaked.
>
> - skb A goes to napi_gro_receive() while it is still in skbuff[A],
>    still DMA mapped and not on free_map. The driver still treats it
>    as a posted buffer.
>
> - On close or reset, ibmveth_free_buffer_pool() finds skb A in
>    skbuff[A], unmaps it and calls dev_kfree_skb_any() on it after the
>    stack has already freed it.
>
> The copybreak and bad-frame paths would recycle slot B instead of A
> in the same way.
>
> ibmveth_rxq_correlator_valid() does not catch this, because both
> correlators can be in range and name live skbs.
>
> PHYP should not rewrite an entry once the toggle is set. But this
> patch treats the correlator as untrusted, and the changelog says it
> is read once. Should ibmveth_rxq_harvest_buffer() take the correlator
> from its caller, so poll uses one value for lookup, bound check and
> harvest? The new KUnit harvest test could read the ring entry itself
> before calling it.
>
> [ ... ]
>
>> +			pool = correlator >> 32;
>> +			room = min_t(unsigned int, skb_tailroom(skb),
>> +				     adapter->rx_buff_pool[pool].buff_size);
>> +			off = offset;
>> +			len = length;
>> +			if (unlikely(len < ETH_HLEN || off >= room ||
>> +				     len > room - off)) {
>> +				if (net_ratelimit())
>> +					netdev_err(netdev,
>> +						   "bad RX frame offset %u length %u (buffer %u), dropping\n",
>> +						   off, len, room);
>> +				ibmveth_rxq_harvest_buffer(adapter, true);
>> +				netdev->stats.rx_dropped++;
>> +				frames_processed++;
>> +				continue;
>> +			}
> [Severity: High]
>
> The commit message says this check fixes the case where "the checksum
> helpers would write past a short frame". Is an ETH_HLEN minimum enough
> for that?
>
> Once this check passes, ibmveth_poll() and its helpers assume a full IP
> header and TCP header and never look at skb->len:
>
> ibmveth_poll()
>      iph_check = iph->check;
>      ibmveth_rx_mss_helper()     /* lrg_pkt or iph_check == 0xffff */
>          skb_shinfo(skb)->gso_size = ntohs(tcph->check);
>          tcph->check = 0;
>          hdr_len = offset + tcph->doff * 4;
>          skb_shinfo(skb)->gso_segs =
>                  DIV_ROUND_UP(skb->len - hdr_len, ...);
>      ibmveth_rx_csum_helper()    /* csum_good */
>          iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
>          struct tcphdr *tcph = (struct tcphdr *)(skb->data + iphlen);
>          if (tcph->check == 0x0000) {
>              tcph->check = ~csum_tcpudp_magic(...);
>
> A frame of about 14 to 92 bytes passes the new check, but these helpers
> still read and write past the end of the frame. In
> ibmveth_rx_mss_helper(), skb->len - hdr_len can also wrap.
>
> On the copybreak path, those accesses land in the uninitialized tailroom
> of new_skb.
>
> On the non-copybreak path, they land in the pool buffer past the frame.
> That path runs when the GFP_ATOMIC copybreak allocation fails, or when
> rx_copybreak is set at or below the frame length.
>
> The new bound also accepts a short frame at the very end of the buffer.
> For pool 0 with room = 512, off = room - 34 and len = 34 leave
> skb->tail == skb->end after skb_put(). eth_type_trans() then leaves 20
> bytes of IPv4 header, so tcph sits at skb->end.
>
> Wouldn't the tcph->check writes then land in struct skb_shared_info
> (hwtstamps, gso_type, tskey or dataref, depending on ihl)?
> skb_partial_csum_set() rejects this only after the write has already
> happened.
>
> Should there be per-protocol skb->len checks, or pskb_may_pull(), before
> the IP and TCP headers are parsed, rather than a fixed minimum?
>
> [Severity: High]
>
> This isn't a bug introduced by this patch, but since this patch hardens
> the RX path: should ibmveth_rx_csum_helper() check iph->ihl before it
> calls ip_fast_csum()?
>
>      if (iph->check == 0xffff) {
>          iph->check = 0;
>          iph->check = ip_fast_csum((unsigned char *)iph,
>                                    iph->ihl);
>      }
>
> On ppc64, ip_fast_csum_nofold() in arch/powerpc/include/asm/checksum.h
> documents that ihl "is always >= 5" and does:
>
>      for (i = 0; i < ihl - 1; i++, ptr++)
>          s += *ptr;
>
> ihl is unsigned, so with ihl == 0, ihl - 1 wraps to 0xFFFFFFFF and the
> loop reads about 16 GiB starting at the RX buffer, in NAPI softirq
> context.
>
> The ihl, check and ethertype fields and the IBMVETH_RXQ_CSUM_GOOD flag
> all come from the sending partition. Could a single IPv4 frame with
> ihl = 0 and check = 0xffff from a peer on the same virtual LAN oops or
> stall this partition?
>
> [ ... ]
>
>> @@ -1581,10 +1661,16 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
>>   	if (ibmveth_rxq_pending_buffer(adapter) && napi_schedule(napi)) {
>>   		lpar_rc = h_vio_signal(adapter->vdev->unit_address,
>>   				       VIO_IRQ_DISABLE);
>> +		rescheduled = 1;
>>   		goto restart_poll;
>>   	}
>>   
>>   out:
>> +	/* napi_schedule() already queued us. Returning budget would
>> +	 * make busy_poll_stop() queue the napi a second time.
>> +	 */
>> +	if (rescheduled && budget && frames_processed >= budget)
>> +		return budget - 1;
>>   	return frames_processed;
>>   }
> [Severity: High]
>
> Does returning budget - 1 cover the case where threaded NAPI and busy
> polling are both enabled?
>
> busy_poll_stop() clears NAPI_STATE_IN_BUSY_POLL before it calls the
> driver poll. Its own comment says "Unless rc == budget we no longer own
> the NAPI instance". From there:
>
> busy_poll_stop()
>    ibmveth_poll()
>      napi_complete_done()             /* succeeds */
>      h_vio_signal(..., VIO_IRQ_ENABLE)
>      napi_schedule()
>        ____napi_schedule()
>          set_bit(NAPI_STATE_SCHED_THREADED, &napi->state);
>          wake_up_process(thread);
>      goto restart_poll;               /* keeps processing the ring */
>
> The woken kthread sees NAPI_STATE_SCHED_THREADED in napi_thread_wait()
> and calls __napi_poll()->ibmveth_poll() on another CPU. Meanwhile the
> original call is still running from restart_poll.
>
> Can the two pollers then race, with no lock, on rx_queue.index and
> toggle, rx_buff_pool[].skbuff[], free_map and producer_index? For
> example, one harvest with reuse=false could clear and unmap an skb while
> the other poller passes the same skb to napi_gro_receive().
>
> The budget - 1 return only runs after this overlap. Continuing to poll
> after napi_schedule() predates this patch, but this patch now reasons
> about NAPI ownership after napi_schedule(). Would it be better to stop
> processing once napi_schedule() succeeds, instead of jumping back to
> restart_poll?
>

  reply	other threads:[~2026-10-12  5:04 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-09 18:32 [PATCH net-next v3 0/8] ibmveth: fix hangs, use-after-frees and netpoll races Mingming Cao
2026-10-09 18:32 ` [PATCH net-next v3 1/8] ibmveth: fix netpoll races with RX replenish Mingming Cao
2026-10-09 18:32 ` [PATCH net-next v3 2/8] ibmveth: do not close twice after a failed reopen Mingming Cao
2026-10-09 18:32 ` [PATCH net-next v3 3/8] ibmveth: disable the reset work before unregister in remove Mingming Cao
2026-10-09 18:32 ` [PATCH net-next v3 4/8] ibmveth: step past bad RX correlators instead of spinning or oopsing Mingming Cao
2026-10-10 19:33   ` netdev-bot+sashiko
2026-10-12  5:03     ` mingming cao [this message]
2026-10-09 18:32 ` [PATCH net-next v3 5/8] ibmveth: release the pool kobjects when probe fails Mingming Cao
2026-10-09 18:32 ` [PATCH net-next v3 6/8] ibmveth: return the error when set_channels cannot add TX queues Mingming Cao
2026-10-09 18:32 ` [PATCH net-next v3 7/8] ibmveth: wait for in-flight transmits in ibmveth_close() Mingming Cao
2026-10-09 18:32 ` [PATCH net-next v3 8/8] ibmveth: wait for the RX poll to return before freeing the RX queue Mingming Cao

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=93cc87b4-14ce-43d9-a29e-d9a6795bb0d5@linux.ibm.com \
    --to=mmc@linux.ibm.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=bjking1@linux.ibm.com \
    --cc=chleroy@kernel.org \
    --cc=davem@davemloft.net \
    --cc=davemarq@linux.ibm.com \
    --cc=edumazet@kernel.org \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=maddy@linux.ibm.com \
    --cc=mpe@ellerman.id.au \
    --cc=netdev-bot+sashiko@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=nnac123@linux.ibm.com \
    --cc=npiggin@gmail.com \
    --cc=pabeni@redhat.com \
    --cc=ritesh.list@gmail.com \
    --cc=sshegde@linux.ibm.com \
    --cc=stephen@networkplumber.org \
    /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