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:24:30 +0200 [thread overview]
Message-ID: <48990076-414c-4196-99b9-86fce41b8054@iogearbox.net> (raw)
In-Reply-To: <20260916170406.1280954-2-bestswngs@gmail.com>
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));
+ if (!encap && skb->encapsulation)
+ bpf_lwt_reset_cb(skb);
switch (ret) {
case BPF_OK:
next prev parent reply other threads:[~2026-09-17 18:24 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-16 17:04 [PATCH v2] bpf: clear stale IPv4 options after LWT encapsulation Weiming Shi
2026-09-17 18:24 ` Daniel Borkmann [this message]
2026-09-17 18:54 ` Daniel Borkmann
2026-09-19 8:22 ` Weiming Shi
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=48990076-414c-4196-99b9-86fce41b8054@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