netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jakub Kicinski <kuba@kernel.org>
To: steffen.klassert@secunet.com
Cc: Jakub Kicinski <kuba@kernel.org>,
	davem@davemloft.net, herbert@gondor.apana.org.au,
	netdev@vger.kernel.org
Subject: Re: [PATCH 01/12] xfrm: iptfs: fix stack OOB read in iptfs_skb_reset_frag_walk()
Date: Tue,  8 Sep 2026 15:48:02 -0700	[thread overview]
Message-ID: <20260908224803.1587019-1-kuba@kernel.org> (raw)
In-Reply-To: <20260907093020.2228346-2-steffen.klassert@secunet.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.
---
xfrm: iptfs: fix stack OOB read in iptfs_skb_reset_frag_walk()

This adds an up-front range check to iptfs_skb_can_add_frags() so that
iptfs_skb_reset_frag_walk() is never entered with an offset at or beyond
the end of the walk's fragment data, where its unbounded advance loop
would read past walk->frags[]. The guard mirrors the one already present
in iptfs_skb_add_frags().

> diff --git a/net/xfrm/xfrm_iptfs.c b/net/xfrm/xfrm_iptfs.c
> index 597aedeac26eb..2ce15c472cc4d 100644
> --- a/net/xfrm/xfrm_iptfs.c
> +++ b/net/xfrm/xfrm_iptfs.c
> @@ -416,6 +416,14 @@ static bool iptfs_skb_can_add_frags(const struct sk_buff *skb,
>  	if (skb_has_frag_list(skb) || skb->pp_recycle != walk->pp_recycle)
>  		return false;
>  
> +	/* Reject an @offset that is at or beyond the end of the walk's data
> +	 * before calling iptfs_skb_reset_frag_walk(), whose fragment-advance
> +	 * loop is otherwise unbounded and would index past walk->frags[].
> +	 * This mirrors the guard already present in iptfs_skb_add_frags().
> +	 */
> +	if (!walk->nr_frags || offset >= walk->total + walk->initial_offset)
> +		return false;
> +

[Severity: Medium]

Should this return true (or be conditioned on len) instead of false?

In the iptfs_reassem_cont() path the walk is prepared and then queried
with the same offset:

net/xfrm/xfrm_iptfs.c:iptfs_reassem_cont() {
	...
	fraglen = min(blkoff, remaining);
	copylen = min(fraglen, ipremain);

	if (!skb_has_frag_list(skb) && !skb_has_frag_list(newskb) &&
	    (skb->head_frag || skb->len == skb->data_len) &&
	    skb->pp_recycle == newskb->pp_recycle) {
		fragwalk = &_fragwalk;
		iptfs_skb_prepare_frag_walk(skb, data, fragwalk);
	}

	if (fragwalk &&
	    iptfs_skb_can_add_frags(newskb, fragwalk, data, copylen)) {
	...
}

Since offset == walk->initial_offset == data here, the new clause reduces
to walk->total == 0, and iptfs_skb_prepare_frag_walk() sums exactly
skb->len - data, so it only fires when data == skb->len, i.e. when
remaining == 0 and therefore copylen == 0 as well.

For that case the guard now sends control into the else branch:

	} else {
		if (skb_linearize(newskb)) {
			...
		}

		/* copy fragment data into newskb */
		if (skb_copy_seq_read(st, data, skb_put(newskb, copylen),
				      copylen)) {
			XFRM_INC_STATS(xs_net(xtfs->x),
				       LINUX_MIB_XFRMINBUFFERERROR);
			goto abandon;
		}
	}

with copylen == 0 and data == skb->len.  skb_copy_seq_read() calls
skb_seq_read() before it looks at len:

net/core/skbuff.c:skb_copy_seq_read() {
	for (;;) {
		sqlen = skb_seq_read(offset, &data, st);
		if (sqlen == 0)
			return -EINVAL;
		if (sqlen >= len) {
	...
}

and skb_seq_read() returns 0 once abs_offset >= st->upper_offset, so the
zero-length copy returns -EINVAL and iptfs_reassem_cont() takes the
abandon label, where iptfs_reassem_abort() frees xtfs->ra_newskb and
destroys the in-progress inner packet reassembly.

Before this patch the same input took the sharing branch: can_add_frags()
fell through its "while (len && fragi < walk->nr_frags)" loop with len == 0
and returned true, iptfs_skb_add_frags() returned immediately via its own
!walk->nr_frags check, and reassembly continued via
"if (copylen < ipremain) xtfs->ra_wantseq++;".

Two inputs from a peer on an IPTFS SA appear to reach this: an AGGFRAG
payload carrying only the basic/CC header with block_offset >= ipremain
while a reassembly is in progress, and the "newskb->len < iphlen" block
copying exactly iphremain == remaining bytes so that "data += copylen"
leaves data == skb->len.

Would a guard on len, for example returning true when len == 0 and only
rejecting when there is data left to add, close the stack out-of-bounds
read without changing the reassembly outcome?

The other caller, iptfs_pskb_add_frags() in __input_process_payload(), is
only reached when capturelen > iphlen and remaining >= iphlen, so it does
not appear to be able to hit the new guard.

For reference, this behaviour is unchanged through the rest of the series:
the only later change to net/xfrm/xfrm_iptfs.c is the ra_runt iplen check
in "xfrm: iptfs: fix runt reassembly panic from short inner tot_len", and
iptfs_skb_can_add_frags() is the same at the end of the series.

  reply	other threads:[~2026-09-08 22:48 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-07  9:29 [PATCH 0/12] pull request (net): ipsec 2026-09-07 Steffen Klassert
2026-09-07  9:29 ` [PATCH 01/12] xfrm: iptfs: fix stack OOB read in iptfs_skb_reset_frag_walk() Steffen Klassert
2026-09-08 22:48   ` Jakub Kicinski [this message]
2026-09-14 10:37     ` Steffen Klassert
2026-09-15  8:31       ` Roshan Kumar
2026-09-07  9:29 ` [PATCH 02/12] xfrm: serialize state GC with device state flush Steffen Klassert
2026-09-08 22:48   ` Jakub Kicinski
2026-09-14 11:23     ` Steffen Klassert
2026-09-14 12:14       ` Chengfeng Ye
2026-09-07  9:29 ` [PATCH 03/12] xfrm: add missing RCU read lock in xfrm_send_migrate_state() Steffen Klassert
2026-09-07  9:29 ` [PATCH 04/12] xfrm: iptfs: fix runt reassembly panic from short inner tot_len Steffen Klassert
2026-09-08 22:48   ` Jakub Kicinski
2026-09-14  9:19     ` Steffen Klassert
2026-09-07  9:29 ` [PATCH 05/12] ipv6: xfrm: use full sockets in local error paths Steffen Klassert
2026-09-08 22:48   ` Jakub Kicinski
2026-09-14  9:25     ` Steffen Klassert
2026-09-07  9:29 ` [PATCH 06/12] xfrm: fix compat ALLOCSPI request use-after-free Steffen Klassert
2026-09-07  9:29 ` [PATCH 07/12] xfrm: add missing rcu_read_lock(), skb_dst_force() and dev_hold() for xfrm_trans_reinject() Steffen Klassert
2026-09-08 22:48   ` Jakub Kicinski
2026-09-14 11:30     ` Steffen Klassert
2026-09-07  9:29 ` [PATCH 08/12] xfrm: use hlist_del_init_rcu for state_cache and state_cache_input Steffen Klassert
2026-09-08 22:48   ` Jakub Kicinski
2026-09-07  9:29 ` [PATCH 09/12] esp: downgrade zerocopy managed frags before mutating skb frags Steffen Klassert
2026-09-08 22:49   ` Jakub Kicinski
2026-09-14  9:55     ` Steffen Klassert
2026-09-07  9:29 ` [PATCH 10/12] xfrm: hold net_device reference under RCU in bundle creation Steffen Klassert
2026-09-08 22:49   ` Jakub Kicinski
2026-09-14  9:57     ` Steffen Klassert
2026-09-07  9:29 ` [PATCH 11/12] xfrm: save input state data before secpath resets Steffen Klassert
2026-09-07  9:29 ` [PATCH 12/12] net: xfrm: reject unrepresentable espintcp transport headers Steffen Klassert
2026-09-08 22:49   ` Jakub Kicinski
2026-09-14 10:22     ` Steffen Klassert
2026-09-09  6:38 ` Some clarifications on the upstreaming process (was: [PATCH 0/12] pull request (net): ipsec 2026-09-07) Steffen Klassert
2026-09-09  9:23   ` Some clarifications on the upstreaming process Paolo Abeni
2026-09-09 10:22     ` Matthieu Baerts
2026-09-10  8:17       ` Steffen Klassert
2026-09-10  8:35         ` Matthieu Baerts
2026-09-10  9:28           ` Steffen Klassert
2026-09-09 10:23     ` Steffen Klassert
2026-09-09 10:34       ` Paolo Abeni
2026-09-09 10:44         ` Steffen Klassert
2026-09-09 18:57           ` Jakub Kicinski
2026-09-10  8:29             ` Matthieu Baerts
2026-09-10  9:02             ` Steffen Klassert
2026-09-14 11:34             ` Steffen Klassert

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=20260908224803.1587019-1-kuba@kernel.org \
    --to=kuba@kernel.org \
    --cc=davem@davemloft.net \
    --cc=herbert@gondor.apana.org.au \
    --cc=netdev@vger.kernel.org \
    --cc=steffen.klassert@secunet.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;
as well as URLs for NNTP newsgroup(s).