All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jakub Kicinski <kuba@kernel.org>
To: syjcnss@gmail.com
Cc: Jakub Kicinski <kuba@kernel.org>,
	davem@davemloft.net, edumazet@google.com, pabeni@redhat.com,
	horms@kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, stable@vger.kernel.org
Subject: Re: [PATCH net] net: pktgen: fix out-of-bounds write in pktgen_finalize_skb()
Date: Mon,  3 Aug 2026 14:25:37 -0700	[thread overview]
Message-ID: <20260803212537.2171760-1-kuba@kernel.org> (raw)
In-Reply-To: <20260729031252.54476-1-syjcnss@gmail.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.
---
--- Patch [1]: [PATCH net] net: pktgen: fix out-of-bounds write in pktgen_finalize_skb() ---
commit 482871be2b4cb4112bd717673de3a4fe3ab0b9c3
Author: Yuejie Shi <syjcnss@gmail.com>

net: pktgen: fix out-of-bounds write in pktgen_finalize_skb()

The patch changes the per-fragment length in pktgen_finalize_skb() from a
truncating division to DIV_ROUND_UP(), and adds an i < frags bound to the
fragment fill loop, so the loop can no longer write past
skb_shinfo(skb)->frags[].  The reported KASAN overflow with pkt_size in
[69675, 69689] and frags 17 does look fixed by this.

> diff --git a/net/core/pktgen.c b/net/core/pktgen.c
> index ee64f3012321..60dbe60005eb 100644
> --- a/net/core/pktgen.c
> +++ b/net/core/pktgen.c
> @@ -2843,8 +2843,8 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
>  		}
>  
>  		i = 0;
> -		frag_len = min_t(int, datalen / frags, PAGE_SIZE);
> -		while (datalen > 0) {
> +		frag_len = min_t(int, DIV_ROUND_UP(datalen, frags), PAGE_SIZE);
> +		while (datalen > 0 && i < frags) {

[Severity: Medium]
[Finding: main-2-0]
[Sources: opus-5]
With frag_len rounded up, can the partition now run out of bytes before
i reaches frags - 1, so that the else branch over-charges the last
fragment?

frag_len is computed once and never re-clamped against the bytes still
outstanding, and only the i == (frags - 1) branch uses min(datalen,
PAGE_SIZE):

		/*last fragment, fill rest of data*/
		if (i == (frags - 1))
			skb_frag_fill_page_desc(&skb_shinfo(skb)->frags[i],
						pkt_dev->page, 0,
						min(datalen, PAGE_SIZE));
		else
			skb_frag_fill_page_desc(&skb_shinfo(skb)->frags[i],
						pkt_dev->page, 0, frag_len);

		datalen -= skb_frag_size(&skb_shinfo(skb)->frags[i]);
		skb->len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
		skb->data_len += skb_frag_size(&skb_shinfo(skb)->frags[i]);

Taking pkt_size 77 with frags 17, which the pkt_size setter accepts since
it only clamps against 14 + 20 + 8:

  fill_packet_ipv4():   datalen = 77 - 42 = 35
  pktgen_finalize_skb(): datalen -= sizeof(*pgh) -> 19
  frag_len = DIV_ROUND_UP(19, 17) = 2

Iterations i = 0..8 consume 18 bytes and leave 1 byte.  At i == 9 the
i == (frags - 1) test is false (frags - 1 is 16), so the else branch
charges the full frag_len of 2:

  datalen becomes -1
  skb->len and skb->data_len are 1 byte larger than requested
  nr_frags ends at 10 instead of the requested 17

Another example is datalen 71 with frags 17: frag_len is 5, 15 iterations
consume 75 bytes, overshooting by 4, and nr_frags ends at 15.  The
overshoot is bounded by frag_len - 1, so at most 16 bytes with
MAX_SKB_FRAGS == 17, and fragment sizes still never exceed PAGE_SIZE, so
this is a length-accounting problem rather than a memory-safety one.

Does the inflated skb->len leave the frame inconsistent with the L3/L4
headers?  fill_packet_ipv4() writes the lengths from the same datalen it
hands to pktgen_finalize_skb():

	udph->len = htons(datalen + 8);	/* DATA + udphdr */
	...
	iplen = 20 + 8 + datalen;
	iph->tot_len = htons(iplen);

fill_packet_ipv6() follows the same pattern.  pktgen_xmit() also does
pkt_dev->last_pkt_size = pkt_dev->skb->len, which feeds
pkt_dev->tx_bytes, so the reported byte counts would drift from the
configured pkt_size too.

Before this change these same inputs partitioned exactly: with datalen 19
and frags 17 the truncated frag_len was 1, giving 16 one-byte fragments
plus a last fragment of 3, and the i == (frags - 1) branch was always
reached.

Would using min(datalen, frag_len) in the else branch, or treating
datalen <= frag_len as the last fragment, keep the sum equal to datalen
in these cases?

The commit message says:

    the fragments now cover datalen exactly and the loop always terminates
    on the last one.  As a side effect pktgen stops emitting zero-length
    fragments when datalen < frags.

Should this also mention that for small datalen with many fragments the
loop terminates before the last fragment, and that fewer fragments than
requested are produced?
-- 
pw-bot: cr

      reply	other threads:[~2026-08-03 21:25 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-29  3:12 [PATCH net] net: pktgen: fix out-of-bounds write in pktgen_finalize_skb() Yuejie Shi
2026-08-03 21:25 ` Jakub Kicinski [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=20260803212537.2171760-1-kuba@kernel.org \
    --to=kuba@kernel.org \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=stable@vger.kernel.org \
    --cc=syjcnss@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.