From: Andrea Mayer <andrea.mayer@uniroma2.it>
To: Ren Wei <weir@nebusec.ai>, Xiang Mei <xmei5@asu.edu>
Cc: netdev@vger.kernel.org, davem@davemloft.net, edumazet@kernel.org,
kuba@kernel.org, pabeni@redhat.com, horms@kernel.org,
pablo@netfilter.org, contact@proelbtn.com, vega@nebusec.ai,
sashiko-bot@kernel.org, petalzu987@gmail.com,
stefano.salsano@uniroma2.it,
Andrea Mayer <andrea.mayer@uniroma2.it>
Subject: Re: [PATCH net 1/1] seg6: validate state in netfilter continuations
Date: Sat, 3 Oct 2026 19:32:08 +0200 [thread overview]
Message-ID: <20261003193208.6e43539a8381ca6bc776bd53@uniroma2.it> (raw)
In-Reply-To: <8e22f1e0a04d4a48bd990872490e21bfc61f9223.1790748418.git.petalzu987@gmail.com>
On Thu, 1 Oct 2026 02:08:53 +0800
Ren Wei <weir@nebusec.ai> wrote:
> From: Zixuan Chai <petalzu987@gmail.com>
>
> Netfilter hooks can drop or replace the dst while an SRv6 packet is
> queued for continuation. The seg6local callbacks must not assume that
> skb_dst() still carries the state for the route being processed.
>
> Validate the destination and SEG6_LOCAL state before using it in the
> End.DX4/End.DX6 continuations and seg6_local_input_core(). The
> seg6_iptunnel continuations must also resolve the SEG6 state beneath
> an XFRM dst and hold a reference while processing the SRH.
>
> Fixes: 7a3f5b0de364 ("netfilter: add netfilter hooks to SRv6 data plane")
> Cc: stable@vger.kernel.org
> Reported-by: Vega <vega@nebusec.ai>
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/all/20260720204430.1886091-1-xmei5@asu.edu/
> Assisted-by: LLM
> Signed-off-by: Zixuan Chai <petalzu987@gmail.com>
> Signed-off-by: Ren Wei <weir@nebusec.ai>
Hi,
Thanks for the patch.
A similar fix was posted by Xiang Mei in July [1]. It got review
comments and no new version yet. Xiang, are you still working on it?
Xiang's v2 1/2 makes the same seg6_local.c changes as this patch. On
that patch I suggested adding unlikely() to the new checks, as in patch
2/2. The same applies here.
For net, I would only check the state and drop the packet, as Xiang's
v2 does, with the limit already discussed on v1 and v2 (the check is on
the type, not on the instance). That check alone stops the crash, also
when SNAT and an XFRM policy replace the dst. Looking through the XFRM
dst is not needed for this fix.
The cover letter has a reproducer, but the commit message, which stays
in the git log, should say how the crash was triggered and how the fix
was tested.
> [snip]
> diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
> index 61c6a27bf202..e3d36fb0f290 100644
> --- a/net/ipv6/seg6_iptunnel.c
> +++ b/net/ipv6/seg6_iptunnel.c
> [snip]
> @@ -60,6 +62,26 @@ static inline struct seg6_lwt *seg6_lwt_lwtunnel(struct lwtunnel_state *lwt)
> return (struct seg6_lwt *)lwt->data;
> }
>
> +static struct lwtunnel_state *seg6_lwt_state(struct dst_entry *dst)
> +{
> + dst = xfrm_dst_path(dst);
> + return dst->lwtstate;
> +}
> +
> +static struct lwtunnel_state *seg6_lwt_state_get(struct sk_buff *skb)
> +{
> + struct lwtunnel_state *lwtst;
> +
> + if (!skb_valid_dst(skb))
> + return NULL;
> +
> + lwtst = seg6_lwt_state(skb_dst(skb));
> + if (!lwtst || lwtst->type != LWTUNNEL_ENCAP_SEG6)
> + return NULL;
> +
> + return lwtstate_get(lwtst);
The route that carries the lwtstate holds a reference on it, and drops
it only after an RCU grace period. Which path needs the one taken by
lwtstate_get()? Sashiko asks the same question [2].
> [snip]
> @@ -557,18 +577,16 @@ static int seg6_input_finish(struct net *net, struct sock *sk,
> static int seg6_input_core(struct net *net, struct sock *sk,
> struct sk_buff *skb)
> {
> - struct dst_entry *orig_dst = skb_dst(skb);
> struct dst_entry *dst = NULL;
> struct lwtunnel_state *lwtst;
> struct seg6_lwt *slwt;
> int err;
>
> - /* We cannot dereference "orig_dst" once ip6_route_input() or
> - * skb_dst_drop() is called. However, in order to detect a dst loop, we
> - * need the address of its lwtstate. So, save the address of lwtstate
> - * now and use it later as a comparison.
> - */
> - lwtst = orig_dst->lwtstate;
> + lwtst = seg6_lwt_state_get(skb);
> + if (!lwtst) {
> + err = -EINVAL;
> + goto drop;
> + }
This comment explains why the lwtstate address is saved before
ip6_route_input() or skb_dst_drop() and compared after them. This still
holds after the patch: seg6_input_route() calls one of them between the
save and the comparison. I don't see a reason to remove the comment
here.
> [snip]
[1] https://lore.kernel.org/all/20260728215448.1543553-1-xmei5@asu.edu/
[2] https://netdev-ai.bots.linux.dev/sashiko/#/patchset/8e22f1e0a04d4a48bd990872490e21bfc61f9223.1790748418.git.petalzu987@gmail.com
Ciao,
Andrea
prev parent reply other threads:[~2026-10-03 17:32 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-30 18:08 [PATCH net 0/1] seg6: validate state in netfilter continuations Ren Wei
2026-09-30 18:08 ` [PATCH net 1/1] " Ren Wei
2026-10-03 17:32 ` Andrea Mayer [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=20261003193208.6e43539a8381ca6bc776bd53@uniroma2.it \
--to=andrea.mayer@uniroma2.it \
--cc=contact@proelbtn.com \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pablo@netfilter.org \
--cc=petalzu987@gmail.com \
--cc=sashiko-bot@kernel.org \
--cc=stefano.salsano@uniroma2.it \
--cc=vega@nebusec.ai \
--cc=weir@nebusec.ai \
--cc=xmei5@asu.edu \
/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