From: Daniel Borkmann <daniel@iogearbox.net>
To: Weiming Shi <bestswngs@gmail.com>,
Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
Martin KaFai Lau <martin.lau@linux.dev>,
Song Liu <song@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
Jiri Olsa <jolsa@kernel.org>,
Emil Tsalapatis <emil@etsalapatis.com>,
Ihor Solodrai <ihor.solodrai@linux.dev>,
John Fastabend <john.fastabend@gmail.com>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>
Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org,
netdev@vger.kernel.org, Peter Oskolkov <posk@google.com>,
Xiang Mei <xmei5@asu.edu>,
stable@vger.kernel.org
Subject: Re: [PATCH v2] bpf: clear stale IPv4 options after LWT encapsulation
Date: Thu, 17 Sep 2026 20:54:32 +0200 [thread overview]
Message-ID: <97695bef-507a-403a-84ae-c2e222b3dc65@iogearbox.net> (raw)
In-Reply-To: <48990076-414c-4196-99b9-86fce41b8054@iogearbox.net>
On 9/17/26 8:24 PM, Daniel Borkmann wrote:
> On 9/16/26 7:04 PM, Weiming Shi wrote:
>> bpf_lwt_push_ip_encap() rebases the network header after prepending an IP
>> header, but leaves IPCB(skb)->opt describing the inner IPv4 header. An
>> ingress LWT route can consequently make an ICMP error interpret an
>> inner-header byte as an option length and copy 255 bytes into 40 bytes of
>> stack storage. The trace decoded with scripts/decode_stacktrace.sh is:
>>
>> BUG: KASAN: stack-out-of-bounds in __ip_options_echo
>> Write of size 255
>> Call Trace:
>> <IRQ>
>> __asan_memcpy (mm/kasan/shadow.c:106)
>> __ip_options_echo (net/ipv4/ip_options.c:96)
>> __icmp_send (net/ipv4/icmp.c:949)
>> ip_forward (net/ipv4/ip_forward.c:176)
>> lwtunnel_input (net/core/lwtunnel.c:465)
>> ip_rcv (net/ipv4/ip_input.c:612)
>> __netif_receive_skb_one_core (net/core/dev.c:6264)
>> process_backlog (net/core/dev.c:6728)
>> __napi_poll (net/core/dev.c:7787)
>> net_rx_action (net/core/dev.c:8007)
>> handle_softirqs (kernel/softirq.c:645)
>> do_softirq.part.0 (kernel/softirq.c:546)
>> </IRQ>
>> <TASK>
>> __local_bh_enable_ip (kernel/softirq.c:473)
>> __dev_queue_xmit (net/core/dev.c:4961)
>> packet_sendmsg (net/packet/af_packet.c:3143)
>> __sys_sendto (net/socket.c:2281)
>> __x64_sys_sendto (net/socket.c:2288)
>> do_syscall_64 (arch/x86/entry/syscall_64.c:84)
>> entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
>> </TASK>
>>
>> A helper-only reset can be restored by bpf_prog_run_save_cb(), while a
>> program without ctx->cb[] access can clone-redirect the skb before a
>> return-only reset. Track active LWT runs and their control-block family
>> in the BPF network context. When the control block is not BPF scratch
>> space, save its original contents and reset it immediately so clones see
>> the new-family layout. After the program returns, restore that snapshot
>> when the verdict continues through the original protocol callback, then
>> invalidate the stale header metadata. Verdicts that reroute or redirect
>> keep the new-family layout.
>>
>> Preserve the state across nested runs and retain the ingress interface and
>> L3-slave state when the protocol family changes.
>>
>> Cc: stable@vger.kernel.org
>> Fixes: 52f278774e79 ("bpf: implement BPF_LWT_ENCAP_IP mode in bpf_lwt_push_encap")
>> Reported-by: Xiang Mei <xmei5@asu.edu>
>> Assisted-by: LLM
>> Signed-off-by: Weiming Shi <bestswngs@gmail.com>
>> ---
>> v2:
>> - Save the incoming protocol control block for programs without ctx->cb[]
>> access.
>> - Restore that snapshot before a verdict continues through the original
>> protocol callback, then invalidate the rebased header metadata.
>> - Keep the eager new-family reset for clones and final reroute/redirect
>> consumers.
>> - Add Cc: stable@vger.kernel.org.
>> - Correct the patch author and reporter attribution.
>> v1:
>> - https://lore.kernel.org/bpf/20260915170147.3943392-2-bestswngs@gmail.com/
>
> Hm, this is way too much fragile churn for a feature which I'm not sure is much
> used (?). Can't we just save/restore the skb->cb when the BPF prog runs? Roughly
> sth along these lines (untested) :
>
> diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c
> index da49364ec63d..9cf04b44ecc1 100644
> --- a/net/core/lwt_bpf.c
> +++ b/net/core/lwt_bpf.c
> @@ -36,10 +36,24 @@ static inline struct bpf_lwt *bpf_lwt_lwtunnel(struct lwtunnel_state *lwt)
> #define NO_REDIRECT false
> #define CAN_REDIRECT true
>
> +static void bpf_lwt_reset_cb(struct sk_buff *skb)
> +{
> + if (skb->protocol == htons(ETH_P_IP)) {
> + memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
> + IPCB(skb)->iif = skb->skb_iif;
> + } else if (skb->protocol == htons(ETH_P_IPV6)) {
> + memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
> + IP6CB(skb)->iif = skb->skb_iif;
> + IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
> + }
> +}
> +
> static int run_lwt_bpf(struct sk_buff *skb, struct bpf_lwt_prog *lwt,
> struct dst_entry *dst, bool can_redirect)
> {
> struct bpf_net_context __bpf_net_ctx, *bpf_net_ctx;
> + bool encap = skb->encapsulation;
> + u8 cb_saved[BPF_SKB_CB_LEN];
> int ret;
>
> /* Disabling BH is needed to protect per-CPU bpf_redirect_info between
> @@ -48,7 +62,12 @@ static int run_lwt_bpf(struct sk_buff *skb, struct bpf_lwt_prog *lwt,
> local_bh_disable();
> bpf_net_ctx = bpf_net_ctx_set(&__bpf_net_ctx);
> bpf_compute_data_pointers(skb);
> +
> + memcpy(cb_saved, bpf_skb_cb(skb), sizeof(cb_saved));
> ret = bpf_prog_run_save_cb(lwt->prog, skb);
> + memcpy(bpf_skb_cb(skb), cb_saved, sizeof(cb_saved));
... also needs BPF selftests obviously; dropping the memcpy and a closer look wrt
freplace, whether we should reuse & propagate ->cb_access=1 also from there.
> + if (!encap && skb->encapsulation)
> + bpf_lwt_reset_cb(skb);
>
> switch (ret) {
> case BPF_OK:
prev parent reply other threads:[~2026-09-17 18:54 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-16 17:04 Weiming Shi
2026-09-17 18:24 ` Daniel Borkmann
2026-09-17 18:54 ` Daniel Borkmann [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=97695bef-507a-403a-84ae-c2e222b3dc65@iogearbox.net \
--to=daniel@iogearbox.net \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bestswngs@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=davem@davemloft.net \
--cc=eddyz87@gmail.com \
--cc=edumazet@google.com \
--cc=emil@etsalapatis.com \
--cc=horms@kernel.org \
--cc=ihor.solodrai@linux.dev \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=posk@google.com \
--cc=song@kernel.org \
--cc=stable@vger.kernel.org \
--cc=xmei5@asu.edu \
--cc=yonghong.song@linux.dev \
/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
all inboxes | Powered by JetHome®