Netdev List
 help / color / mirror / Atom feed
* [PATCH net] net: mpls: keep transport offsets valid across label changes
@ 2026-10-11  4:14 Weiming Shi
  2026-10-12  4:17 ` netdev-bot+sashiko
  0 siblings, 1 reply; 2+ messages in thread
From: Weiming Shi @ 2026-10-11  4:14 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman
  Cc: netdev, Xiang Mei, zjamg, Weiming Shi, stable,
	co+b3e1928dd33a1bd6

skb_mpls_push() and skb_mpls_pop() can leave a transport header at or
inside the moved MPLS header behind. Repeated pops then make
skb_transport_offset() negative; when a GSO skb is redirected to egress,
qdisc_pkt_len_segs_init() widens that offset, wraps its pull length, and
dereferences about 4 GiB past skb->data.

For tunnel GSO, qdisc_pkt_len_segs_init() uses the inner transport header
instead. skb_mpls_push() rejects encapsulated skbs because the networking
stack does not support simultaneous tunnel and MPLS GSO, but
skb_mpls_pop() did not. This leaves the same negative-offset path reachable
through stale inner metadata.

Align outer transport headers at or before the affected network header
with its new position while preserving valid later L4 offsets. Reject
encapsulated skbs from skb_mpls_pop(), matching skb_mpls_push(), and
refresh mac_len after a pop.

BUG: unable to handle page fault for address: ffffed10408b8e0b
Oops: Oops: 0000 [#1] SMP KASAN NOPTI
RIP: qdisc_pkt_len_segs_init (include/linux/tcp.h:31 net/core/dev.c:4193)
Call Trace:
 __dev_queue_xmit (net/core/dev.c:4835)
 tcf_mirred_to_dev (net/sched/act_mirred.c:242 net/sched/act_mirred.c:237 net/sched/act_mirred.c:328)
 tcf_mirred_act (net/sched/act_mirred.c:489)
 tcf_action_exec (include/net/tc_wrapper.h:59 net/sched/act_api.c:1162 net/sched/act_api.c:1136)
 tcf_classify (include/net/tc_wrapper.h:178 net/sched/cls_api.c:1779 net/sched/cls_api.c:1875)
 tc_run (net/core/dev.c:4463)
 __netif_receive_skb_core.constprop.0 (net/core/dev.c:4538 net/core/dev.c:6115)
 __netif_receive_skb_one_core (net/core/dev.c:6262)
 netif_receive_skb (net/core/dev.c:6377 net/core/dev.c:6463 net/core/dev.c:6522)
 tun_get_user (drivers/net/tun.c:1595 drivers/net/tun.c:2045)
 tun_chr_write_iter (drivers/net/tun.c:2091)
 vfs_write (fs/read_write.c:595 fs/read_write.c:687)
 ksys_write (fs/read_write.c:739)
 do_syscall_64 (arch/x86/entry/syscall_64.c:61 arch/x86/entry/syscall_64.c:84)
 entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
Kernel panic - not syncing: Fatal exception in interrupt

Cc: stable@vger.kernel.org
Fixes: 48d2ab609b6b ("net: mpls: Fixups for GSO")
Reported-by: <co+b3e1928dd33a1bd6@bugs.sh>
Assisted-by: LLM
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
---
 net/core/skbuff.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index cc3b4b702..c09bb8ac2 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -6612,6 +6612,7 @@ int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto,
 		  int mac_len, bool ethernet)
 {
 	struct mpls_shim_hdr *lse;
+	bool trans_update;
 	int err;
 
 	if (unlikely(!eth_p_mpls(mpls_proto)))
@@ -6630,11 +6631,15 @@ int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto,
 		skb_set_inner_protocol(skb, skb->protocol);
 	}
 
+	trans_update = skb_transport_header_was_set(skb) &&
+		       skb->transport_header <= skb->network_header;
 	skb_push(skb, MPLS_HLEN);
 	memmove(skb_mac_header(skb) - MPLS_HLEN, skb_mac_header(skb),
 		mac_len);
 	skb_reset_mac_header(skb);
 	skb_set_network_header(skb, mac_len);
+	if (trans_update)
+		skb->transport_header = skb->network_header;
 	skb_reset_mac_len(skb);
 
 	lse = mpls_hdr(skb);
@@ -6669,6 +6674,10 @@ int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, int mac_len,
 	if (unlikely(!eth_p_mpls(skb->protocol)))
 		return 0;
 
+	/* Networking stack does not allow simultaneous Tunnel and MPLS GSO. */
+	if (skb->encapsulation)
+		return -EINVAL;
+
 	err = skb_ensure_writable(skb, mac_len + MPLS_HLEN);
 	if (unlikely(err))
 		return err;
@@ -6680,6 +6689,10 @@ int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, int mac_len,
 	__skb_pull(skb, MPLS_HLEN);
 	skb_reset_mac_header(skb);
 	skb_set_network_header(skb, mac_len);
+	if (skb_transport_header_was_set(skb) &&
+	    skb->transport_header <= skb->network_header)
+		skb->transport_header = skb->network_header;
+	skb_reset_mac_len(skb);
 
 	if (ethernet && mac_len >= ETH_HLEN) {
 		struct ethhdr *hdr;

^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-12  4:17 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-11  4:14 [PATCH net] net: mpls: keep transport offsets valid across label changes Weiming Shi
2026-10-12  4:17 ` netdev-bot+sashiko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox