summaryrefslogtreecommitdiff
path: root/net/ipv6
AgeCommit message (Collapse)Author
4 daysipv6: Protect multiple routes insertion by table lock.Kuniyuki Iwashima
syzbot reported the warning below. [0] While call_fib6_multipath_entry_notifiers() is called locklessly, fib6_siblings could be changed concurrently, leading to the warning (and later null-ptr-deref). Let's protect multiple routes insertion with tb6_lock. Along with that, __ip6_ins_rt() and ip6_route_del() are changed to fib6_add() and fib6_del(). Note that fib6_del() finally calls rt6_multipath_rebalance(), which requires rcu_read_lock(). [0]: i != fen6_info->nsiblings WARNING: drivers/net/netdevsim/fib.c:831 at nsim_fib6_event_init drivers/net/netdevsim/fib.c:831 [inline], CPU#0: syz.0.157/6279 WARNING: drivers/net/netdevsim/fib.c:831 at nsim_fib6_prepare_event drivers/net/netdevsim/fib.c:947 [inline], CPU#0: syz.0.157/6279 WARNING: drivers/net/netdevsim/fib.c:831 at nsim_fib_event_schedule_work drivers/net/netdevsim/fib.c:1003 [inline], CPU#0: syz.0.157/6279 WARNING: drivers/net/netdevsim/fib.c:831 at nsim_fib_event_nb+0x1029/0x11d0 drivers/net/netdevsim/fib.c:1043, CPU#0: syz.0.157/6279 Modules linked in: CPU: 0 UID: 0 PID: 6279 Comm: syz.0.157 Not tainted syzkaller #0 PREEMPT(full) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/24/2026 RIP: 0010:nsim_fib6_event_init drivers/net/netdevsim/fib.c:831 [inline] RIP: 0010:nsim_fib6_prepare_event drivers/net/netdevsim/fib.c:947 [inline] RIP: 0010:nsim_fib_event_schedule_work drivers/net/netdevsim/fib.c:1003 [inline] RIP: 0010:nsim_fib_event_nb+0x1029/0x11d0 drivers/net/netdevsim/fib.c:1043 Code: eb 0d 4d 89 fd e8 b7 c5 6c fa be 01 00 00 00 48 89 df e8 5a 38 85 fd 4d 89 ef 4c 8b 6c 24 20 e9 4a f3 ff ff e8 98 c5 6c fa 90 <0f> 0b 90 e9 db fa ff ff 89 e9 80 e1 07 80 c1 03 38 c1 0f 8c df f0 RSP: 0018:ffffc900047bef10 EFLAGS: 00010293 RAX: ffffffff875b59a8 RBX: 0000000000000002 RCX: ffff888079770000 RDX: 0000000000000000 RSI: 0000000000000002 RDI: 0000000000000001 RBP: ffffc900047bf0a0 R08: ffff88805c0bb02f R09: 1ffff1100b817605 R10: dffffc0000000000 R11: ffffed100b817606 R12: dffffc0000000000 R13: 0000000000000000 R14: 0000000000000001 R15: ffff88802c792000 FS: 00007f334ba076c0(0000) GS:ffff888123ad0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f334ba06ff8 CR3: 000000007a5b2000 CR4: 00000000003526f0 Call Trace: <TASK> notifier_call_chain+0x1a5/0x3d0 kernel/notifier.c:85 atomic_notifier_call_chain+0xda/0x180 kernel/notifier.c:223 call_fib_notifiers+0x31/0x60 net/core/fib_notifier.c:36 call_fib6_multipath_entry_notifiers+0xf5/0x160 net/ipv6/ip6_fib.c:428 ip6_route_multipath_add net/ipv6/route.c:5542 [inline] inet6_rtm_newroute+0x14f5/0x1a30 net/ipv6/route.c:5664 rtnetlink_rcv_msg+0x802/0xc00 net/core/rtnetlink.c:7163 netlink_rcv_skb+0x226/0x4a0 net/netlink/af_netlink.c:2572 netlink_unicast_kernel net/netlink/af_netlink.c:1335 [inline] netlink_unicast+0x7bd/0x940 net/netlink/af_netlink.c:1361 netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1916 sock_sendmsg_nosec+0x14e/0x190 net/socket.c:800 __sock_sendmsg net/socket.c:818 [inline] ____sys_sendmsg+0x54e/0x850 net/socket.c:2715 ___sys_sendmsg+0x2a5/0x360 net/socket.c:2769 __sys_sendmmsg+0x273/0x4d0 net/socket.c:2858 __do_sys_sendmmsg net/socket.c:2885 [inline] __se_sys_sendmmsg net/socket.c:2882 [inline] __x64_sys_sendmmsg+0xa0/0xc0 net/socket.c:2882 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline] do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f334ab9e1d9 Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007f334ba07028 EFLAGS: 00000246 ORIG_RAX: 0000000000000133 RAX: ffffffffffffffda RBX: 00007f334ae26090 RCX: 00007f334ab9e1d9 RDX: 04000000000001f2 RSI: 0000200000000000 RDI: 0000000000000004 RBP: 00007f334ac35888 R08: 0000000000000000 R09: 0000000000000000 R10: 00000000000000fc R11: 0000000000000246 R12: 0000000000000000 R13: 00007f334ae26128 R14: 00007f334ae26090 R15: 00007ffd96688aa8 </TASK> Fixes: 169fd62799e8 ("ipv6: Get rid of RTNL for SIOCADDRT and RTM_NEWROUTE.") Reported-by: syzbot+751b587577d0ebca10f2@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/6adbaed6.67317f00.38c4bc.001b.GAE@google.com/T/ Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Eric Dumazet <edumazet@kernel.org> Reviewed-by: David Ahern <dsahern@kernel.org> Link: https://patch.msgid.link/20261027065247.2871134-1-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
4 daysRevert "net: advertise TCP MSS from the configured MTU, not the learned PMTU"Yongjian Wang
This reverts commit 2640e6419594 ("net: advertise TCP MSS from the configured MTU, not the learned PMTU"). That commit stopped the learned PMTU from lowering the MSS we advertise in SYN and SYN-ACK. For symmetric paths it argued that "the peer runs its own PMTU discovery and usually already knows the real path MTU". That only holds if ICMP "fragmentation needed" can reach the peer. When the peer sits behind a firewall that drops inbound ICMP, its PMTU discovery is a black hole (RFC 2923, section 2.1), and the smaller MSS we advertised was the only thing keeping its full-size segments off the narrow hop. Inbound ICMP filtering is very common in enterprise and carrier networks, and it is pervasive in mainland China. We hit this in production after the commit was backported to 6.12.111: TCP connections that reach a server through a relay with a smaller-MTU hop complete the handshake, then stall as soon as the client sends full-size segments. Clients on networks that let ICMP through, and connections that bypass the relay, are unaffected, which made it hard to trace back to the kernel. Reproducer, network namespaces on a single host: cli --(1500)-- r1 --(1456)-- r2 --(1500)-- srv r1 drops ICMP frag-needed towards cli. srv has already learned PMTU 1456 towards cli, then cli uploads 1 MB to srv: kernel SYN-ACK MSS 1 MB upload 6.12.107 1416 OK 6.12.111 1460 stalls, times out 7.3-rc7 1460 stalls, times out 7.3-rc7 + this revert 1416 OK The asymmetric case the commit was written for does not need a new default: the advertised MSS can already be set per route with the advmss metric, which takes precedence over default_advmss(). With this revert applied, on an asymmetric path where srv learned PMTU 1456 towards cli while cli->srv is 1500 end to end: srv route to cli SYN-ACK MSS largest cli->srv segment default 1416 1404 advmss 1460 1460 1448 So DSR-style setups can opt in with "ip route ... advmss <mss>", while hosts whose peers cannot complete PMTU discovery keep working by default. Fixes: 2640e6419594 ("net: advertise TCP MSS from the configured MTU, not the learned PMTU") Closes: https://lore.kernel.org/regressions/4F0FAEB6-A13B-47F3-BFF1-C706686C6F64@gmail.com/ Cc: stable@vger.kernel.org Signed-off-by: Yongjian Wang <echoowall@gmail.com> Reviewed-by: Eric Dumazet <edumazet@kernel.org> Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev> Link: https://patch.msgid.link/20261026-advmss-revert-v1-2-272fa4b7ecb6@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
5 daysinet: frags: prevent acceptance of partially authenticated reassemblyJérémy Jean
A reassembled skb retains the secpath from its first fragment, which makes it possible for the final policy check to accept bytes that were not covered by the transform recorded on the skb. This can affect IPsec tunnel traffic, including AH and ESP, and allow a packet to be accepted even though only part of its payload was authenticated. Reject a fragment when its secpath differs from the fragments already in the queue, and keep overlap statistics limited to actual overlaps. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr> Reviewed-by: Eric Dumazet <edumazet@kernel.org> Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
6 daysipmr: drop packets with unknown ingress VIFZhiling Zou
A packet can race with VIF publication and make ipmr_find_vif() return -1 even though the VIF device pointer is already visible. The parent VIF device check can then pass with an invalid ingress VIF. For (*,G) entries, this can also let the packet be forwarded back out its ingress VIF. Drop packets whose ingress VIF lookup fails in both IPv4 and IPv6 forwarding, before checking the MFC parent device. This prevents forwarding with an unknown ingress VIF and avoids the (*,G) hairpin. Without the early check, the negative index can reach the IPv4 offload lookup only for an skb marked for L3 forwarding offload, currently done by mlxsw. The race is rare; the supplied PoC reports only the UBSAN negative-index diagnostic. Fixes: 4eadb88244d1 ("ipmr: do not acquire mrt_lock while calling ip_mr_forward()") Fixes: 9b1c21d898fd ("ip6mr: do not acquire mrt_lock while calling ip6_mr_forward()") Cc: stable@vger.kernel.org Reported-by: Vega <vega@nebusec.ai> Link: https://lore.kernel.org/netdev/b966eb102e98f299e45be59ada033a8766e4c6df.1791899747.git.zhilinz@nebusec.ai/ Suggested-by: Ido Schimmel <idosch@nvidia.com> Suggested-by: Naman Gulati <namangulati@google.com> Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai> Reviewed-by: Naman Gulati <namangulati@google.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/5271fcb94a4d9e697ed64a348e92ea9e74faab1c.1792608753.git.zhilinz@nebusec.ai Signed-off-by: Jakub Kicinski <kuba@kernel.org>
6 daysipmr, ip6mr: validate packets injected into the register vif on xmitIdo Schimmel
reg_vif_xmit() passes the packet to ipmr_cache_report() which copies its IP header into the IGMPMSG_WHOLEPKT report that is queued to the mroute socket. Nothing guarantees that the packet contains a full IP header, so when a short packet is injected on the register device (e.g., using AF_PACKET), the copy reads past the end of the packet and a recvmsg() on the mroute socket leaks the uninitialized bytes to user space [1]. IPv6 has the same problem [2]. Its reg_vif_xmit() does call pskb_inet_may_pull(), but the helper keys off skb->protocol and does not pull anything when the protocol is neither IPv4 nor IPv6. Fix by dropping packets whose protocol does not match the address family of the register device or that do not contain a full network header. [1] BUG: KMSAN: kernel-infoleak in _copy_to_iter raw_recvmsg Uninit was stored to memory at: ipmr_cache_report reg_vif_xmit packet_sendmsg Uninit was created at: __alloc_skb sock_alloc_send_pskb packet_sendmsg Bytes 1-3 of 21 are uninitialized [2] BUG: KMSAN: kernel-infoleak in _copy_to_iter rawv6_recvmsg Uninit was stored to memory at: ip6mr_cache_report reg_vif_xmit packet_sendmsg Uninit was created at: __alloc_skb sock_alloc_send_pskb packet_sendmsg Bytes 8-23 of 41 are uninitialized Fixes: 14fb64e1f449 ("[IPV6] MROUTE: Support PIM-SM (SSM).") Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Reported-by: Sashiko <netdev-bot+sashiko@kernel.org> Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/0545f0c83f5ee2f6696210f87268e811ef655715.1792476357.git.zhilinz%40nebusec.ai Signed-off-by: Ido Schimmel <idosch@nvidia.com> Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn> Reviewed-by: Eric Dumazet <edumazet@kernel.org> Link: https://patch.msgid.link/20261025071729.34967-3-idosch@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
11 daysMerge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/netPaolo Abeni
Merge in late fixes in preparation for the net-next PR. Conflicts: net/netfilter/nf_conntrack_netlink.c cd37ab22a74e0 ("netfilter: nf_conntrack_netlink: fix inverted IPv6 tuple filter") 1ae2d094b0200 ("netfilter: ctnetlink: fix inverted IPv6 address match in dump filter") Adjacent changes: drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c 8830e65ed46de ("net: use assign_bit() where applicable") 07bd391eb957 ("octeontx2-af: Fix CQ enable state tracking after AQ writes") net/core/sock.c 31c5ea8a3296 ("ipv6: Remove IPV6_ADDRFORM.") 31b564f70d88 ("net: use the full socket in sk_mc_loop()") net/mptcp/protocol.h 0cb6910130a3 ("mptcp: remove thmac from subflow ctx") 7538fa33bb2f ("mptcp: fix subflow bitfield misuse") Signed-off-by: Paolo Abeni <pabeni@redhat.com>
12 daysMerge tag 'nf-26-10-19' of ↵Jakub Kicinski
git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf Pablo Neira Ayuso says: ==================== Netfilter/IPVS fixes for net The following patchset contains Netfilter/IPVS for net: 1) Fix IPv6 nexthdr offset truncation in fragment reassembly, this has been uncovered by LLM, from Jeremy Jean. 2) Restrict checksums in nfqueue to known protocols and offset, after this patch the plan is to re-enable nfqueue in userns, this came via LLM report. from Florian Westhphal. 3) Fix races when handling overload flag in IPVS, this patch is not perfect but Julian considers this improves the situation. This was uncovered by LLM. From Julian Anastasov. 4) Error handling for IPVS sync_threshold sysctl, from Joel Granados. 5) Use skb_vlan_tag_get_id() to retrieve the VLAN id, discard tci bits, when handling VLAN in the flowtable, from Shuangfeng He. 6) Initialize IPCB for inet/ingress reject, uncovered by LLM. 7) Restrict completion of binary search array to anonymous set. 8) Restrict DCCP option matching to avoid out-of-bound read, from Sung Byeongchan. 9) Reset transport header offset in flowtable after tunnel decapsulation to fix issue with qdisc xmit path, from Lorenzo Bianconi. 10) Fix inverted matching in ctnetlink dump filtering, from Liu Chao. * tag 'nf-26-10-19' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: nf_conntrack_netlink: fix inverted IPv6 tuple filter netfilter: flowtable: reset transport header after nf_flow_encap_pop() netfilter: xt_dccp: handle reserved options as single-byte netfilter: nft_set_rbtree: narrow down range completion to anonymous sets netfilter: nf_reject: initialize IPCB at inet ingress netfilter: flowtable: use the vlan id, not the full tci, in the tuple key ipvs: skip committing sync_threshold when proc_dointvec fails ipvs: fix more races around the overload flag netfilter: nft_payload: restrict checksum offsets to known values netfilter: nf_conntrack: avoid truncating IPv6 nexthdr offset ==================== Link: https://patch.msgid.link/20261019150249.1879516-1-pablo@netfilter.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
12 daysipv6: Hold RCU when emitting route hardware flags notificationIdo Schimmel
fib6_info_hw_flags_set() is called by drivers from process context without RTNL or RCU. When the route uses a nexthop object, rt6_nlmsg_size() and rt6_fill_node() access the nexthop's RCU protected nexthop info and group pointers via rcu_dereference_rtnl(), resulting in suspicious RCU usage splats [1]. Fix by holding RCU while sizing and filling the notification, like fib_alias_hw_flags_set() already does. Switch to GFP_ATOMIC for the skb allocation accordingly. Reproducer: # echo "10 0" > /sys/bus/netdevsim/new_device # sysctl -wq net.ipv6.fib_notify_on_flag_change=1 # sysctl -wq net.ipv4.nexthop_compat_mode=1 # ip -6 nexthop add id 1 blackhole # ip -6 route add 2001:db8:1::1/128 nhid 1 [1] WARNING: suspicious RCU usage 7.3.0-rc7-virtme-g191aa41548b2 #38 Not tainted net/ipv4/nexthop.c:1539 suspicious rcu_dereference_check() usage! [...] Workqueue: events nsim_fib_event_work Call Trace: <TASK> dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120) lockdep_rcu_suspicious.cold (kernel/locking/lockdep.c:6972) nexthop_for_each_fib6_nh (net/ipv4/nexthop.c:1539 (discriminator 16)) rt6_nlmsg_size (net/ipv6/route.c:5728) fib6_info_hw_flags_set (net/ipv6/route.c:6503) nsim_fib6_rt_add (drivers/net/netdevsim/fib.c:671 drivers/net/netdevsim/fib.c:694) nsim_fib6_rt_insert (drivers/net/netdevsim/fib.c:759) nsim_fib_event_work (drivers/net/netdevsim/fib.c:856 drivers/net/netdevsim/fib.c:889 drivers/net/netdevsim/fib.c:1493) process_one_work (kernel/workqueue.c:3396) worker_thread (kernel/workqueue.c:3479 kernel/workqueue.c:3560) kthread (kernel/kthread.c:436) ret_from_fork (arch/x86/kernel/process.c:158) ret_from_fork_asm (arch/x86/entry/entry_64.S:245) </TASK> Fixes: 907eea486888 ("net: ipv6: Emit notification when fib hardware flags are changed") Reported-by: Sashiko <netdev-bot+sashiko@kernel.org> Closes: https://lore.kernel.org/netdev/179152182668.434549.18232968419539498055@kernel.org/ Signed-off-by: Ido Schimmel <idosch@nvidia.com> Reviewed-by: Eric Dumazet <edumazet@kernel.org> Reviewed-by: David Ahern <dsahern@kernel.org> Link: https://patch.msgid.link/20261019140337.2886875-2-idosch@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
12 daysip6mr: clear skb->cb[] in reg_vif_xmit()Eric Dumazet
reg_vif_xmit() hands the skb to ip6mr_cache_report() as an MRT6MSG_WHOLEPKT report. skb_realloc_headroom() copies skb->cb[] into the report, which is queued to the mroute socket, where rawv6_recvmsg() reads it as IP6CB. By the time the pim6reg device transmits the packet, skb->cb[] is not IP6CB anymore: qdisc_pkt_len_init() overwrites iif and ra, and any qdisc installed on the device (fq, fq_codel, pie, cake...) or a tc BPF program writing skb->cb[] fills the area holding dst0, srcrt, dst1, lastopt and flags. Since commit dd433671fef3 ("ipv6: validate extension header length before copying to cmsg") these stale offsets can no longer cause out-of-bounds reads, but the mroute socket can still receive bogus IPV6_PKTINFO ifindex and extension header ancillary data. Clear IP6CB before building the report. The skb is freed right after, so nothing else depends on its control block. Fixes: 14fb64e1f449 ("[IPV6] MROUTE: Support PIM-SM (SSM).") Signed-off-by: Eric Dumazet <edumazet@kernel.org> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
12 daysMerge tag 'nf-next-26-10-18' of ↵Jakub Kicinski
git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next Pablo Neira Ayuso says: ==================== Netfilter updates for net-next The following patchset contains Netfilter/IPVS updates for net-next: 1) Disable br_netfilter in userns and schedule it for removal in 2027, from Florian Westphal. 2) Update selftest nft_queue.sh to make it more stable on debug kernels, from Jakub Kicinski. 3) Fix a overflow in IPVS sync messages which can only happen in very old 2.6 kernels, from Julian Anastasov. 4) Finer grain packet drop in nfnetlink_queue when dependency objects are going away, from Antonio Ojea. 5) Add a selftest for the nfnetlink_queue packet drop case, also from Antonio Ojea. 6) Flush conntrack gc worker when existing netns to address a unlikely UaF, from Florian Westphal. 7) Switch nf_tables chain types to use rcu, otherwise module removal can trigger UaF, also from Florian. 8) Remove redundant parsing in nft_exthdr for the tcp options case, from Fernando F. Mancera. 9) Remove redundant skb_header_pointer() calls in nft_exthdr for tcp options, from Fernando F. Mancera. 10) Fix conntrack_vrf.sh selftest return value in zone subtest, from Florian Westphal. 11) Restrict raw table in nft_compat to specific family, hook and priority, from Florian Westphal. Prepare the flowtable to support for IPv4 over IPv6 tunneling and vice-versa, this includes 4 patches from Lorenzo Bianconi. 12) Explicitly set inner protocol when popping header, this is not needed for the existing IPIP and IP6IP6 case because skb->protocol remains the same. 13) Simplify tuple tunnel information fill up when parsing outer tunnel IP headers. 14) Add a new encap_proto which determines the outer tunnel protocol family. 15) Prepare flowtable forwarding path to deal with mixed IPv4-IPv6 tunnels. * tag 'nf-next-26-10-18' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next: netfilter: flowtable: unify tunnel push for IPv4 and IPv6 netfilter: flowtable: add encap_proto to flow_offload_tunnel netfilter: flowtable: populate tunnel tuple regardless of inner protocol netfilter: flowtable: set inner protocol when popping tunnel header netfilter: nft_compat: restrict raw table targets/matches selftests: netfilter: fix return value in zone subtest netfilter: nft_exthdr: avoid 60 bytes stack buffer in TCP option mangling netfilter: nft_exthdr: remove redundant op parsing in tcp_set_init netfilter: nf_tables: switch chain_types array to rcu netfilter: conntrack: fix unlikely UaF in gc worker selftests: netfilter: nft_queue: check the scope of the hook drop flush netfilter: nf_queue: limit the hook drop flush to the unregistered hook point ipvs: fix buffer overflow when sending sync messages selftests: netfilter: nft_queue.sh: only queue icmp echo request/reply netfilter: disable br_netfilter in user namespaces ==================== Link: https://patch.msgid.link/20261018005638.1776148-1-pablo@netfilter.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
12 daysipv6: account route exceptions to the netns of their dstEric Dumazet
rt6_insert_exception() and rt6_remove_exception() update rt6_stats->fib_rt_cache of dev_net(rt6i->dst.dev), but the device of an exception dst can move to another netns while the exception is still in its bucket. This happens when the bucket is flushed from an RCU callback, for instance from nexthop_free_rcu() for the nh_info of a replaced nexthop, whose exceptions still point to live routes. If the device moves to another netns before that callback runs, the decrement hits the other netns, whose u32 counter underflows in /proc/net/rt6_stats, while the counter of the original netns never goes back down. Account exceptions to the netns their dst was allocated in, derived from dst->ops as ip6_dst_gc() already does, which does not depend on the device. The dst already relies on that netns' ip6_dst_ops being alive when it is destroyed, which happens after the exception is removed. Fixes: 81eb8447daae ("ipv6: take care of rt6_stats") Signed-off-by: Eric Dumazet <edumazet@kernel.org> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261016091556.2750902-1-edumazet@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
12 daysipv6: do not restart DAD for a dead ifaddrDaehyeon Ko
addrconf_dad_failure() can create a stable-privacy replacement without RTNL. After ipv6_add_addr() publishes it, addrconf_ifdown() can mark the new ifaddr DEAD, clear its route, and unlink it before the recovery path takes ifp2->lock. The recovery path then unconditionally changes the state back to PREDAD and queues delayed DAD work. The MTU teardown path can leave IF_READY set. For an optimistic address, addrconf_dad_begin() can consequently pass the cleared NULL route to ip6_ins_rt(). This follow-on was found by source review and was not separately triggered at runtime. The new ifaddr is already initialized in PREDAD. Under ifp2->lock, record the retry and queue DAD only if teardown has not changed the state to DEAD. If teardown wins after this check, the work observes DEAD and exits without reviving the address. This complements the existing lock_errdad check that preserves the original ifaddr's DEAD state after the same function reacquires its lock. Fixes: 5f40ef77adb2 ("ipv6: do retries on stable privacy addresses") Cc: stable@vger.kernel.org Reported-by: Sashiko <netdev-bot+sashiko@kernel.org> Closes: https://lore.kernel.org/r/179161099408.434549.14449036924552933828@kernel.org Link: https://lore.kernel.org/r/20260513025509.3776405-1-lilinmao@kylinos.cn Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261015050651.1841557-5-4ncienth@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
12 daysipv6: initialize temporary ifaddr before publicationDaehyeon Ko
ipv6_create_tempaddr() holds a reference to the public ifaddr, publishes the new temporary address through ipv6_add_addr(), and only then stores the reference and final timestamps. addrconf_ifdown() can remove the temporary address before ifpub is stored, leaking the public ifaddr reference. Publishing ifpub alone is insufficient: manage_tempaddrs() can then find the object before cstamp and tstamp are final, update its lifetimes, and have the constructor overwrite its timestamp with an older value. This follow-on was found by source review and was not separately triggered at runtime. Pass the public ifaddr and both timestamps in ifa6_config. Initialize all three fields before adding the temporary address to either the hash or per-device lists. On success the existing public-ifaddr reference transfers to the temporary object. On error it remains owned and released by ipv6_create_tempaddr(). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Reported-by: Sashiko <netdev-bot+sashiko@kernel.org> Closes: https://lore.kernel.org/r/179122559913.434549.12720841717630168470@kernel.org Link: https://lore.kernel.org/r/179161099665.434549.5858601179492551889@kernel.org Link: https://lore.kernel.org/r/20261007164548.GA1153540@shredder Link: https://lore.kernel.org/r/20261012145240.GA779501@shredder Suggested-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261015050651.1841557-4-4ncienth@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
12 daysipv6: serialize address publication with device teardownDaehyeon Ko
ipv6_add_addr() checks idev state before allocating an ifaddr, but publishes the object later. addrconf_ifdown() can mark and detach the idev between the check and publication. This happens when a non-loopback device MTU falls below IPV6_MIN_MTU. A forced interleaving published an address on a dead idev, and ipv6_get_ifaddr() still returned it after teardown. Later device deletion remained blocked with: unregister_netdevice: waiting for ac0 to become free. Usage count = 3 Protect the dead indication with idev->lock and keep that lock across both hash and device-list publication. Recheck dead before publishing; if teardown wins the lock, reject the unpublished object. Non-unregister teardown does not set dead. The preceding change covers an add that misses the initial hash scan but reaches the per-device list snapshot. Both changes are required when backporting this fix. Fixes: 8814c4b53381 ("[IPV6] ADDRCONF: Convert addrconf_lock to RCU.") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/179161099408.434549.14449036924552933828@kernel.org Link: https://lore.kernel.org/r/20261012145306.GB779501@shredder Suggested-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261015050651.1841557-3-4ncienth@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
12 daysipv6: remove ifaddr from hash during ifdown list cleanupDaehyeon Ko
addrconf_ifdown() clears the address hash before snapshotting the per-device address list. A concurrent ipv6_add_addr() can publish an address after the hash scan and before the list snapshot. The ifdown path then removes the address from the device list and drops the list-owned reference while it is still linked in the hash. Once the remaining references are released, inet6_ifa_finish_destroy() warns, but a DEAD address continues to kfree_rcu(). The hash therefore points to freed memory that later RCU walkers can dereference. This follow-on was found by source review and was not separately triggered at runtime. Remove each non-kept address from the hash immediately before removing it from the per-device list. Keeping it hashed through the delete notification blocks same-address publication until NETDEV_DOWN has been delivered. hlist_del_init_rcu() is safe when the earlier hash scan already removed the address. This handles a late publisher captured by the list snapshot. The next change serializes publication with teardown so an add cannot miss both observations. Both changes are required when backporting the complete fix. Fixes: 73a8bd74e261 ("ipv6: Revert 'administrative down' address handling changes.") Cc: stable@vger.kernel.org Reported-by: Ido Schimmel <idosch@nvidia.com> Link: https://lore.kernel.org/r/20261004135117.GA206930@shredder Link: https://lore.kernel.org/r/179161099539.434549.2238120015372268173@kernel.org Suggested-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261015050651.1841557-2-4ncienth@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
13 daysnet: skbuff: replace skb_page_unref() and __skb_frag_unref() with ↵Mina Almasry
skb_netmem_unref() Unreferencing a page_pool fragment with recycle=false decrements the non-pp backing refcount instead of pp_ref_count, underflowing the page refcount when the fragment was owned via page_pool (as on mlx4's RX error path). Having both skb_page_unref() and __skb_frag_unref(frag, recycle) made it easy for callers to pass hardcoded recycle=false on SKB-owned fragments. Replace skb_page_unref() and __skb_frag_unref() with skb_netmem_unref(netmem, recycle), which dispatches to napi_pp_put_page() when recycle is true and put_netmem() otherwise: - Use skb_frag_unref(skb, ...) on SKB-owned fragments in mlx4, sky2, tls_strp, and skb_shift() so unrefs always match skb->pp_recycle. - Use put_netmem() directly in tls_device's destroy_record(), which releases raw non-pp page references outside an SKB. Found by code inspection and confirmed with the KUnit tests added later in this series; not observed in production. The mlx4, sky2, and TLS call-site changes are compile-tested only. Assisted-by: LLM Signed-off-by: Mina Almasry <almasrymina@google.com> Link: https://patch.msgid.link/20261014173945.373295-4-almasrymina@google.com Acked-by: Stanislav Fomichev <sdf@fomichev.me> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
14 daysnetfilter: nf_reject: initialize IPCB at inet ingressKyle Zeng
The inet ingress hook runs before ip_rcv_core() and ip6_rcv_core(), so neither IPCB nor IP6CB has been initialized when nft_reject_inet passes a packet to nf_send_unreach() or nf_send_unreach6(). skb->cb can therefore retain metadata from an earlier protocol layer. For IPv4, icmp_send() treats IPCB(skb)->opt as parsed IPv4 options. Stale option offsets can make __ip_options_echo() copy an attacker-controlled length into its 40-byte reply option buffer and overflow the stack. On an unpatched v7.2-rc5 kernel, the IPv4 reproducer produced: BUG: KASAN: stack-out-of-bounds in __ip_options_echo() Write of size 255 For IPv6, icmpv6_send() consumes IP6CB(skb) as parsed IPv6 metadata. It always uses iif for source selection and, when MIP6 is enabled, uses dsthao as an extension-header offset. These fields must not be stale. For NF_INET_INGRESS, clear the address-family-specific control block and restore its input interface before constructing the ICMP error. This matches similar initialization normally performed by ip_rcv_core() and ip6_rcv_core(). Fixes: 117ca1f8920c ("netfilter: nft_reject_inet: allow to use reject from inet ingress") Cc: stable@vger.kernel.org Assisted-by: Codex:gpt-5.6-sol Codex:gpt-5.5-cyber Signed-off-by: Kyle Zeng <kylebot@openai.com> Co-developed-by: David Lee <david.lee@trailofbits.com> Signed-off-by: David Lee <david.lee@trailofbits.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
14 daysnetfilter: nf_conntrack: avoid truncating IPv6 nexthdr offsetJérémy Jean
find_prev_fhdr() returns the offset of the Next Header field before an IPv6 Fragment header through an int pointer, but stores the offset in a u8 local. An extension header chain can put this field beyond byte 255, causing the offset to wrap before it is saved in the fragment queue. Reassembly later uses the wrapped value to update the preceding Next Header field. This overwrites another byte in the IPv6 header chain and can make conntrack parse a different transport tuple from the one used by IPv6 local delivery. A two-fragment packet can, for example, be recorded as UDP destination port 53 while its payload is delivered to UDP port 9999. Use int for the working offset, matching the output argument and the other offset variables in this path. Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.") Assisted-by: Codex:gpt-5 Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2026-10-18netfilter: flowtable: add encap_proto to flow_offload_tunnelLorenzo Bianconi
Add encap_proto (AF_INET or AF_INET6) to struct flow_offload_tunnel to allow its use as part of the hash table key during flowtable entry lookup. This is a preliminary change to support IPv4 over IPv6 tunneling via the flowtable infrastructure for software acceleration. Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2026-10-16calipso: update payload_len when removing the CALIPSO optionJoas Antonio dos Santos
calipso_skbuff_delattr() removes the CALIPSO option from the hop-by-hop extension header, or the whole extension header if CALIPSO is its only option, and pulls the skb by the removed length. It never updates ipv6hdr->payload_len, so after a successful removal the header still claims the original length. calipso_skbuff_setattr() already adjusts payload_len by the length it adds; the delete path was missed. This is reached on the forward path when a packet carrying CALIPSO is sent to a destination mapped to an unlabeled NetLabel domain. The forwarded packet then has a payload_len larger than its real payload by the removed length (8 to 264 bytes), and the receiver drops it as truncated. So removing the label on the forward path has been broken for every packet that is not resegmented later (SYN, UDP, ICMPv6...). Adjust payload_len after the header is moved. BIG TCP packets carry payload_len == 0 (see ipv6_set_payload_len()), and ipv6_payload_len() then falls back to skb->len, so leave them alone. Tested with client, router and server network namespaces on one kernel (arm64, QEMU): SELinux permissive with a minimal mdp-generated policy (network_peer_controls=1), "netlabelctl calipso add pass doi:16", the default NetLabel mapping left unlabeled, IPv6 forwarding on the router. The client sends 5 UDP datagrams with a CALIPSO hop-by-hop option (DOI 16, set through IPV6_HOPOPTS) to the server through the router: before: router Ip6OutForwDatagrams 5, server receives 0, server Ip6InTruncatedPkts 5 after: router Ip6OutForwDatagrams 5, server receives 5, server Ip6InTruncatedPkts 0 Fixes: 2917f57b6bc1 ("calipso: Allow the lsm to label the skbuff directly.") Signed-off-by: Joas Antonio dos Santos <joasantonio108@gmail.com> Link: https://patch.msgid.link/179147329205.58079.5847298721173675285@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-15ipv6: defrag: orphan skb before queuingZixuan Chai
IPv4 and nf_conntrack fragment queues orphan skbs before returning -EINPROGRESS, but ip6_frag_queue() leaves the socket association intact. Commit 18685451fc4e ("inet: inet_defrag: prevent sk release while still in use") moved skb_orphan() into ip_frag_queue() and nf_ct_frag6_queue(), but missed ip6_frag_queue(). Without orphaning, inet_frag_reasm_finish() clears fp->sk on frag_list skbs but leaves fp->destructor set to sock_pfree. Freeing the reassembled skb then calls sock_pfree() with a NULL socket. A socket using SOCK_RCU_FREE may also be released while its fragment is queued, leaving a stale socket pointer; this is a second consequence of the same missing orphan. Orphan the skb before returning -EINPROGRESS so the queued fragment no longer retains the socket association or destructor. Fixes: cf7fbe660f2d ("bpf: Add socket assign support") Cc: stable@vger.kernel.org Reported-by: Vega <vega@nebusec.ai> Reviewed-by: Eric Dumazet <edumazet@kernel.org> Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de> Signed-off-by: Zixuan Chai <petalzu987@gmail.com> Signed-off-by: Ren Wei <weir@nebusec.ai> Link: https://patch.msgid.link/5c396b7011168cd98b9812df4d6bbd00a96048e7.1791008591.git.petalzu987@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-15net: erspan: set lltx to avoid sch_direct_xmit deadlockYun Zhou
The ERSPAN xmit path re-enters the network stack, causing nested acquisition of _xmit_lock on the underlay device while already holding the ERSPAN device's _xmit_lock, creating an ABBA deadlock. This happens for both IPv4 ERSPAN (erspan_xmit() -> ip_tunnel_xmit()) and IPv6 ERSPAN (ip6erspan_tunnel_xmit() -> ip6_tnl_xmit()): sch_direct_xmit [lock erspan] -> erspan_xmit -> ip_tunnel_xmit -> ip_output -> __dev_queue_xmit -> sch_direct_xmit [lock underlay] sch_direct_xmit [lock erspan] -> ip6erspan_tunnel_xmit -> ip6_tnl_xmit -> ip6_output -> __dev_queue_xmit -> sch_direct_xmit [lock underlay] Set dev->lltx = true so HARD_TX_LOCK() skips the spinlock for ERSPAN. This is safe as the ERSPAN xmit path has no shared mutable state: o_seqno is atomic, TX stats are per-CPU u64_stats, dst_cache is per-CPU, and o_flags is no longer modified in the xmit path since commit 9958e69b9893 ("gre: fix ERSPAN o_flags race/corruption in xmit and fill_info"). GRETAP, the sibling device with identical xmit structure, already sets lltx. Reported-by: syzbot+9bda1b9fbb7fbdf9b62b@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=9bda1b9fbb7fbdf9b62b Fixes: 84e54fe0a5ea ("gre: introduce native tunnel support for ERSPAN") Fixes: 5a963eb61b7c ("ip6_gre: Add ERSPAN native tunnel support") Cc: stable@vger.kernel.org # 9958e69b9893 ("gre: fix ERSPAN o_flags race/corruption in xmit and fill_info") Cc: stable@vger.kernel.org Signed-off-by: Yun Zhou <yun.zhou@windriver.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261008093824.119453-1-yun.zhou@windriver.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-15Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/netJakub Kicinski
Cross-merge networking fixes after downstream PR (net-7.3-rc8). No conflicts. Adjacent changes: drivers/net/ethernet/microchip/lan865x/lan865x.c 2a3f6d2a9ac3 ("microchip: lan865x: move setting of netops to fix crash") 15358c2c3dca ("net: ethernet: oa_tc6: return ERR_PTR from oa_tc6_init()") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-15calipso: keep BIG TCP payload_len in calipso_skbuff_setattr()Joas Antonio dos Santos
calipso_skbuff_setattr() adjusts payload_len by the length of the option it inserts or resizes: payload = ntohs(ip6_hdr->payload_len); ip6_hdr->payload_len = htons(payload + len_delta); GRO can build BIG TCP packets larger than IPV6_MAXPLEN, and stores payload_len == 0 for them; ipv6_payload_len() then falls back to skb->len. For such a packet forwarded to a destination mapped to CALIPSO, the code above writes len_delta (or 65536 + len_delta when shrinking) into payload_len, and ipv6_payload_len() no longer falls back to skb->len. nf_tables, conntrack and sch_cake rely on it. The same arithmetic also wraps when a packet grows past IPV6_MAXPLEN, and a BIG TCP packet that shrinks below IPV6_MAXPLEN should get its real length back. Set payload_len from the skb length with ipv6_set_payload_len(), which stores 0 above IPV6_MAXPLEN and the real length otherwise, as ipv6_gro_complete() does. The network header was just reset to skb->data, so skb->len - sizeof(*ip6_hdr) is the payload length. Tested on one kernel (arm64, QEMU) with SELinux permissive, a minimal mdp-generated policy (network_peer_controls=1), "netlabelctl calipso add pass doi:16" and a NetLabel mapping of fd00:2::/64 to CALIPSO DOI 16. calipso_skbuff_setattr() was called through netlbl_skbuff_setattr() from a test-only debugfs hook (not part of this patch) adding a level-only label; payload_len after the call: case before fix after fix real length 1000, unlabeled 1016 1016 1016 70000 GSO, payload_len 0 16 0 70016 65530 GSO, grows past MAXPLEN 10 0 65546 65540 GSO with a 24 byte hop header, shrinks below MAXPLEN 65528 65532 65532 1000 with a 24 byte hop header 992 992 992 (0 means ipv6_payload_len() returns the real length.) On the forward path, with a client injecting unlabeled UDP through a router to a server, the router adds the CALIPSO option and the server delivers all datagrams (Udp6InDatagrams 5, Ip6InTruncatedPkts 0) with this patch. Fixes: 81fbc812132c ("ipv6/gro: insert temporary HBH/jumbo header") Suggested-by: Eric Dumazet <edumazet@kernel.org> Suggested-by: Wang Zhan <wang.zhan@smartx.com> Signed-off-by: Joas Antonio dos Santos <joasantonio108@gmail.com> Assisted-by: Claude:claude-opus-5-5 Reviewed-by: Wang Zhan <wang.zhan@smartx.com> Acked-by: Paul Moore <paul@paul-moore.com> Link: https://patch.msgid.link/179156155963.36253.400481753322266658@gmail.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-10-15net: ipv6: seg6: report lwtunnel setup errors via extackGabriel Goller
seg6_build_state() rejected invalid configurations with a generic -EINVAL, so "ip route add ... encap seg6 ..." sometimes reported "Invalid argument". Add extack messages to the checks that lacked one, and use NL_REQ_ATTR_CHECK() for the missing SRH attribute so that userspace can tell which attribute is missing. The checks themselves and their return values are unchanged. Signed-off-by: Gabriel Goller <g.goller@proxmox.com> Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn> Reviewed-by: Andrea Mayer <andrea.mayer@uniroma2.it> Link: https://patch.msgid.link/20261009152015.462383-1-g.goller@proxmox.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-10-13calipso: hash the cache key, not the option start, in calipso_cache_add()Joas Antonio dos Santos
calipso_cache_add() stores calipso_ptr + 2 as the cache key, but computes entry->hash over calipso_ptr, i.e. starting two bytes earlier at the option type and length. calipso_opt_getattr() looks entries up with calipso_cache_check(calipso + 2, calipso[1], ...), which hashes the key itself. The two hashes only match on a jhash collision, so the CALIPSO label cache never hits and every labelled packet takes the full DOI lookup and category conversion path. The memcmp() on the key keeps lookups correct, so this is a performance bug only. Hash the stored key, as cipso_v4_cache_add() does for CIPSO. Fixes: 4fee5242bf41 ("calipso: Add a label cache.") Signed-off-by: Joas Antonio dos Santos <joasantonio108@gmail.com> Assisted-by: Claude:claude-opus-5-5 Reviewed-by: Daniel Machon <daniel.machon@microchip.com> Link: https://patch.msgid.link/179138670045.80227.16155454353416856947@gmail.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-10-08Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/netJakub Kicinski
Cross-merge networking fixes after downstream PR (net-7.3-rc7). Conflicts: include/net/strparser.h 0984ebc631792 ("strparser: make sure __strp_recv isn't running before tearing down the parser") 02fd0a2111374 ("net: strparser: removed the aborted bit and aborts counter") https://lore.kernel.org/asYfmLsfy-SCxXjr@sirena.co.uk Adjacent changes: Documentation/networking/strparser.rst 5f193cdabf25 ("docs: networking: strparser: remove general mode") 0984ebc63179 ("strparser: make sure __strp_recv isn't running before tearing down the parser") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-08ip6_gre: let collect_md ip6gretap send from the unspecified addressAnton Danilov
ip6gre_xmit_ipv6() drops an IPv6 packet whose source address equals the tunnel remote, to avoid a trivial tunneling loop. On a collect_md ip6gretap device t->parms.raddr is not the exit point: the outer destination comes from the per-packet tunnel metadata. Such devices are normally created without a remote, so raddr is ::, and the check never matches a real tunnel endpoint. It matches every frame sent from the unspecified address instead. On an L2 tunnel those frames are regular link traffic. Duplicate Address Detection sends its Neighbor Solicitations from :: (RFC 4862, section 5.4.2), and MLD reports are sent from :: while an interface has no link-local address yet (RFC 3590, section 4). Frames bridged into a collect_md ip6gretap device, e.g. with tc tunnel_key and mirred, are dropped even though they carry valid metadata, so DAD cannot detect a duplicate address on the other side of the tunnel. Skip the check for collect_md devices of type ARPHRD_ETHER. It stays for L3 ip6gre, where sending a packet with an unspecified source means forwarding it (RFC 4291, section 2.5.2), and for ip6gretap without collect_md. ip6erspan does not run this check in collect_md mode either. Signed-off-by: Anton Danilov <littlesmilingcloud@gmail.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261005191227.894665-1-littlesmilingcloud@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-08ipv6: do not warn on route notification size raceDaehyeon Ko
fib6_info_hw_flags_set() sizes the skb with rt6_nlmsg_size() and later fills it with rt6_fill_node(). With nexthop compatibility mode enabled, a concurrent replacement can grow the group between these independent snapshots. rt6_fill_node() can then legitimately return -EMSGSIZE, so the warning does not prove a sizing bug. Remove the warning. The existing error path still frees the skb and reports the error to listeners. Fixes: 907eea486888 ("net: ipv6: Emit notification when fib hardware flags are changed") Reported-by: Ido Schimmel <idosch@nvidia.com> Link: https://lore.kernel.org/netdev/20261007114003.GA1011260@shredder/ Suggested-by: Ido Schimmel <idosch@nvidia.com> Cc: stable@vger.kernel.org Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> Link: https://patch.msgid.link/4012604727e5ba80b69ccd4d08796511397ddaef.1791423190.git.4ncienth@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-07ip_tunnel: make __iptunnel_pull_header() return a drop reasonAnton Danilov
__iptunnel_pull_header() returns -ENOMEM whenever it fails. It can fail in two pskb_may_pull() calls, one for the tunnel header and one for the inner Ethernet header of ETH_P_TEB, and in the skb_unclone() done for GSO packets. pskb_may_pull() fails when the packet is shorter than the requested length as well as when pulling from the frags cannot allocate, so a truncated packet and an allocation failure look the same to the callers. The ones that report a drop reason can only pick SKB_DROP_REASON_NOMEM, as vxlan_rcv() does, and so would the GRE receive paths once they report drop reasons. In ip6_gre, gre_rcv() pulls the header before the tunnel lookup, so a packet from any sender whose ETH_P_TEB inner Ethernet header or WCCPv2 extra word is cut short would be reported as an out of memory condition. Make __iptunnel_pull_header() and iptunnel_pull_header() return the reason pskb_may_pull_reason() already computes, SKB_DROP_REASON_NOMEM when skb_unclone() fails, and SKB_NOT_DROPPED_YET on success. A failure is still non-zero, so the callers that only test the result keep working. Three callers, in ip_gre and ip6_gre, test it with "< 0" instead; the enum has no negative values, so that test would always be false, and the compiler does not warn about it. Make them test for a non-zero value. vxlan_rcv() keeps reporting NOMEM for any failure until the next patch has it report the returned reason. Suggested-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: Anton Danilov <littlesmilingcloud@gmail.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261005201417.906344-3-littlesmilingcloud@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-07ipv6: Use ipv6_neigh_lookup() and friends.Kuniyuki Iwashima
syzbot reported the splat below in neigh_mark_dead() [0] where tbl->lock was not held while neigh_ifdown() should have acquired one. This only happens when a neigh_table accidentally has a neighbour from a different netns. In ip6_finish_output2(), the net argument is the caller's and does not always match dev_net(dev) fetched from dst. (e.g. xfrm) It is error-prone to require callers to fetch netns and neigh_table and pass it with dev to neigh_lookup(), etc. Let's replace neigh_lookup() and friends with IPv6 helpers. Note that __neigh_lookup() is split into ipv6_neigh_lookup() and ipv6_neigh_create(). [0]: debug_locks && !(lock_is_held(&(&n->tbl->lock)->dep_map) != 0) WARNING: net/core/neighbour.c:154 at neigh_mark_dead+0x2fb/0x340 net/core/neighbour.c:154, CPU#0: syz.0.857/9765 Modules linked in: CPU: 0 UID: 0 PID: 9765 Comm: syz.0.857 Not tainted syzkaller #0 PREEMPT(full) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/24/2026 RIP: 0010:neigh_mark_dead+0x2fb/0x340 net/core/neighbour.c:154 Code: e8 03 42 80 3c 28 00 74 08 48 89 df e8 ee 9a 80 f8 4c 89 33 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc cc e8 86 95 10 f8 90 <0f> 0b 90 e9 8f fd ff ff 48 c7 c1 80 9a 7a 90 80 e1 07 80 c1 03 38 RSP: 0018:ffffc90003726600 EFLAGS: 00010287 RAX: ffffffff89b7467a RBX: ffff888022e86000 RCX: 0000000000080000 RDX: ffffc900047fa000 RSI: 0000000000003e08 RDI: 0000000000003e09 RBP: 0000000000000000 R08: 0000000000000003 R09: 0000000000000004 R10: dffffc0000000000 R11: fffff520006e4cb8 R12: ffff888022e8613c R13: dffffc0000000000 R14: ffff888022e86020 R15: ffff888022e86000 FS: 00007f9c30f046c0(0000) GS:ffff888124cc6000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 0000000076c56000 CR4: 00000000003526f0 Call Trace: <TASK> neigh_flush_one+0x27c/0x5a0 net/core/neighbour.c:388 neigh_flush_dev net/core/neighbour.c:432 [inline] __neigh_ifdown+0x1fb/0xc70 net/core/neighbour.c:465 neigh_ifdown+0x1f/0x30 net/core/neighbour.c:487 rt6_disable_ip+0x751/0x7e0 net/ipv6/route.c:5058 addrconf_ifdown+0x155/0x1ad0 net/ipv6/addrconf.c:3892 addrconf_notify+0x1bc/0x1050 net/ipv6/addrconf.c:-1 notifier_call_chain+0x1a5/0x3d0 kernel/notifier.c:85 call_netdevice_notifiers_mtu net/core/dev.c:2350 [inline] netif_set_mtu_ext+0x5ac/0x830 net/core/dev.c:9963 do_setlink+0xa81/0x47a0 net/core/rtnetlink.c:3247 rtnl_setlink+0x578/0x820 net/core/rtnetlink.c:3623 rtnetlink_rcv_msg+0x802/0xc00 net/core/rtnetlink.c:7159 netlink_rcv_skb+0x226/0x4a0 net/netlink/af_netlink.c:2572 netlink_unicast_kernel net/netlink/af_netlink.c:1335 [inline] netlink_unicast+0x7bd/0x940 net/netlink/af_netlink.c:1361 netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1916 sock_sendmsg_nosec+0x13a/0x180 net/socket.c:800 __sock_sendmsg net/socket.c:815 [inline] sock_write_iter+0x2de/0x3e0 net/socket.c:1266 do_iter_readv_writev+0x612/0x8c0 fs/read_write.c:-1 vfs_writev+0x343/0x990 fs/read_write.c:1058 do_writev+0x154/0x2e0 fs/read_write.c:1104 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline] do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f9c2ff9e159 Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007f9c30f04028 EFLAGS: 00000246 ORIG_RAX: 0000000000000014 RAX: ffffffffffffffda RBX: 00007f9c30225fa0 RCX: 00007f9c2ff9e159 RDX: 0000000000000001 RSI: 00002000000003c0 RDI: 0000000000000004 RBP: 00007f9c3003506b R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007f9c30226038 R14: 00007f9c30225fa0 R15: 00007ffed3c74808 </TASK> Fixes: df5f4f372de5 ("ipv6: Replace &nd_tbl with nd_table(net).") Reported-by: syzbot+5a8857f0b4a0a7b12c62@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/6abd69a9.80e1c6cc.22483f.0005.GAE@google.com/ Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261003212336.1304988-7-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-07ipv6: Rename ip6_neigh_lookup() to __ip6_dst_neigh_lookup().Kuniyuki Iwashima
Later, we will add ipv6_neigh_lookup() as a wrapper for neigh_lookup(nd_table(net), ...). The existing ip6_neigh_lookup() is called from ip6_dst_neigh_lookup() with a gateway address. Let's rename ip6_neigh_lookup() to __ip6_dst_neigh_lookup(). Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261003212336.1304988-3-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-06ip6_gre: remove obsolete ERSPAN PMTU updateDaehyeon Ko
A tc tunnel_key action can attach a METADATA_IP_TUNNEL dst to an skb, and mirred can redirect it to a native ip6erspan device. The legacy PMTU update in ip6erspan_tunnel_xmit() treats that metadata dst as a route. Since it has no output device, dst_dev(dst)->mtu dereferences NULL. On v7.2 with KASAN, an initial UID/GID 65534 process with CapEff 0 used self-created user and network namespaces to trigger: KASAN: null-ptr-deref RIP: ip6erspan_tunnel_xmit+0x10fc/0x2cc0 Kernel panic - not syncing: Fatal exception in interrupt The update is obsolete. Commit fe1a4ca0a2b7 ("ip6_gre: process toobig in a better way") changed IPv6 GRE Too Big handling to update the underlay route and removed the equivalent block from __gre6_xmit(). ip6_tnl_xmit() then propagates the underlay PMTU to the overlay route. Remove the stale ERSPAN copy and its now-unused dst variable. This eliminates the metadata-dst dereference and keeps ERSPAN aligned with IPv6 GRE PMTU handling. Fixes: 5a963eb61b7c ("ip6_gre: Add ERSPAN native tunnel support") Cc: stable@vger.kernel.org Suggested-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261002033058.358137-1-4ncienth@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-06ipv6: Batch rt6_uncached_list_flush_dev() in netdev_run_todo().Kuniyuki Iwashima
IPv6 uncached routes are linked to the global per-cpu lists, rt6_uncached_list. When unregistering a netdev, rt6_uncached_list_flush_dev() iterates over the potentially long lists to find uncached routes tied to the device and swap it with blackhole_netdev. Since it is called for every device in dying netns under RTNL, it adds O(N_dev x (N_cpu + N_route)) costs to any batched device unregistration. Let's call it once per batched device unregistration without RTNL. Because it now runs without RTNL, rt->dst.dev and rt->rt6i_idev->dev may transition to NETREG_UNREGISTERED at different times. Thus, we must check that both devices are blackhole_netdev before unlinking the route; otherwise, the remaining device reference would not be flushed when the other device is unregistered. In addition, since netdev_run_todo() runs even when IPv6 is disabled, rt6_uncached_list_flush_dev() must check ipv6_mod_enabled() before touching rt6_uncached_list. Note also that netdev_run_todo() cannot be called before rt6_uncached_list is initialised because: 1. unregister_netdevice_many_notify() panics when dev_boot_phase == 1 (net_dev_init() is subsys_initcall()). 2. the only device registered before fs_initcall_sync() is loopback and loopback_net_init() panics in case of failure. Reported-by: Chris J Arges <carges@cloudflare.com> Closes: https://lore.kernel.org/netdev/20260917-hash-bucket-route-lists-v3-0-30493a37b6eb@cloudflare.com/ Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Tested-by: Chris J Arges <carges@cloudflare.com> Link: https://patch.msgid.link/20261001204752.2572265-7-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-06net: Order blackhole_netdev_init(), inet_init(), and inet6_init().Kuniyuki Iwashima
Commit 309b905deee5 ("ipv6: convert CONFIG_IPV6 to built-in only and clean up Kconfigs") started to call inet6_init() as device_initcall(). It explains the reason as a race condition on IPv6 addrconf, but this is not accurate. The change initially used fs_initcall() but switched to device_initcall() due to the null-ptr-deref stack trace in the link below. It happened because blackhole_netdev_init() uses device_initcall() and blackhole_netdev was NULL when addrconf_init() called ipv6_add_dev(blackhole_netdev). Due to the order in Kbuild, $ cat -n Kbuild | grep -E "(drivers|net)" 111 obj-y += drivers/ 114 obj-$(CONFIG_NET) += net/ using device_initcall() for IPv6 allows built-in drivers to be initialised earlier, which requires unnecessary NULL checks. For the same ordering reason, IPv4 uses late_initcall() to initialise blackhole_netdev. Given loopback_net_ops is registered in net_dev_init() at subsys_initcall(), blackhole_netdev_init() can be called after that. In addition, some places assume that IPv4 must be initialised before IPv6. For example, mptcp_proto_v6_init() copies mptcp_prot to mptcp_v6_prot, which would otherwise have NULL mptcp_v6_prot.h.hashinfo. Let's explicitly order blackhole_netdev_init() -> inet_init() -> inet6_init() before device_initcall() with 3 different initcall levels: subsys_initcall : 4 : net_dev_init() subsys_initcall_sync : 4s : blackhole_netdev_init() fs_initcall : 5 : inet_init() fs_initcall_sync : 5s : inet6_init() device_initcall : 6 : built-in drivers Note that both IPv4 and IPv6 can still use fs_initcall() thanks to the order in net/Makefile, but explicit ordering would be less error-prone. $ cat -n net/Makefile | grep ipv 17 obj-$(CONFIG_INET) += ipv4/ 22 obj-y += ipv6/ Link: https://lore.kernel.org/netdev/20260309074758.0ea95a18@kernel.org/ Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Tested-by: Chris J Arges <carges@cloudflare.com> Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de> Link: https://patch.msgid.link/20261001204752.2572265-2-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-05net: psp: require an established connection for association setupDaniel Zahka
Check sk_state under the socket lock in both the rx-assoc and tx-assoc handlers, and only allow association setup on sockets in TCP_ESTABLISHED. Also, fail connect() when PSP assoc state is already present, and remove the dead PSP MSS adjustment from tcp_v[46]_connect(). The net effect of this commit is: 1. PSP assoc state can never exist on a listen socket. 2. The upgrade to PSP must be done while the socket is in TCP_ESTABLISHED. This change defeatures behavior that was previously allowed under the PSP uapi. My justification is: Nothing useful can be done after association setup on closed or listen sockets today. Listen sockets could accept a PSP-encrypted TCP SYN, but the child socket will not inherit any PSP state. On the other side, establishing PSP state prior to connect() will result in a PSP-encrypted TCP SYN sent to a listening peer, which in turn has the aforementioned limitations. That implies that there cannot be any users of this feature, so it should be safe to remove it from the PSP uapi. In theory, the check in the tx-assoc path is more restrictive than necessary. FIN_WAIT1/2, CLOSING, LAST_ACK and CLOSE_WAIT could be allowed, and the peer would accept PSP-encrypted ACKs in the post-FIN-sent states, or data in the half-close case, but it is simpler to disallow those states because they don't fit the upgrade model. The check in the tx-assoc path fixes a bug in commit 6b46ca260e22 ("net: psp: add socket security association code") where an unsynchronized write can be performed on an assoc shared with a timewait socket when the socket is in TCP_CLOSE after shutdown. This commit is not targeted at net because its premise of preventing listen sockets from holding assoc state depends on net-next commit 8cc3aef0cb19 ("tcp: Do not allow buggy transitions between ehash and lhash2.") Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com> Fixes: 6b46ca260e22 ("net: psp: add socket security association code") Reviewed-by: Willem de Bruijn <willemb@google.com> Link: https://patch.msgid.link/20260930-psp-defeat-v2-2-f266e7447129@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-01Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/netJakub Kicinski
Cross-merge networking fixes after downstream PR (net-7.3-rc6). Conflicts: net/mac80211/tx.c net/mac80211/ieee80211_i.h 8effab902fa34 ("wifi: mac80211: prevent AP VLAN tx from other interfaces") 78b843974fb83 ("wifi: mac80211: report multicast transmission from lookup_ra_sta()") https://lore.kernel.org/arJmcuhpJ69wAvYK@sirena.co.uk drivers/net/ethernet/realtek/r8169_main.c 3cdeaef1754ab ("r8169: disable EEE on RTL8168h/8111h") 8a3c76523e449 ("r8169: add support for phylink") https://lore.kernel.org/ar5vAxEqS8tO8aVT@sirena.org.uk Adjacent changes: rust/kernel/net/netlink.rs 5e5916923759 ("rust: net: netlink: Migrate to zerocopy's IntoBytes") 0923198be4ae ("rust: net: netlink: validate attribute length before casting to `c_int`") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-10-01seg6: fix HMAC validation when an extension header precedes the SRHYuya Kusakabe
seg6_hmac_validate_skb() derived the SRH from skb_transport_header(). That only holds while the two coincide, which is not true on the seg6_local input path. ip6_rcv_core() leaves the transport header just past the IPv6 header. A Hop-by-Hop options header is consumed before the route lookup and advances it, but a Destination Options header is not: the seg6_local lwtunnel is entered through an input redirect from the route lookup, which bypasses the extension header handlers. The transport header then still points at the Destination Options header while seg6_get_srh() has located the real SRH further down the chain. The HMAC is therefore computed over the Destination Options header, and a packet carrying a valid HMAC TLV is dropped when seg6_require_hmac is set. Such a packet is legitimate: RFC 8200 allows Destination Options before a routing header, and get_srh() has walked the header chain since commit 5829d70b0b6c ("ipv6: sr: fix get_srh() to comply with IPv6 standard "RFC 8200""). With a Fragment or an Authentication header in front of the SRH, the same mistake also reads past the data pulled by seg6_get_srh(). This happens before seg6_require_hmac is read, so the default configuration is affected. Reproduce by giving a node a seg6local End SID with net.ipv6.conf.<dev>.seg6_require_hmac=1 and a key installed with "ip sr hmac set <keyid> sha1", then sending IPv6 -> Destination Options -> SRH (carrying a valid HMAC TLV) -> payload to that SID: it is dropped, while the same packet without the Destination Options header passes. Fixes: 5829d70b0b6c ("ipv6: sr: fix get_srh() to comply with IPv6 standard "RFC 8200"") Assisted-by: LLM Signed-off-by: Yuya Kusakabe <yuya.kusakabe@gmail.com> Reviewed-by: Andrea Mayer <andrea.mayer@uniroma2.it> Link: https://patch.msgid.link/20260926-b4-seg6-hmac-transport-header-v2-1-8087b76f6375@gmail.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-09-30ipv6: sr: use skb_get_hash_net() in seg6_make_flowlabel()Eric Dumazet
Since commit d58e468b1112 ("flow_dissector: implements flow dissector BPF hook") __skb_flow_dissect() needs a net pointer, either from skb->dev, skb->sk, or since commit 3cbf4ffba5ee ("net: plumb network namespace into __skb_flow_dissect") a caller provided pointer. syzbot was able to reach seg6_make_flowlabel() with an skb having neither skb->dev nor skb->sk set: a TIPC UDP bearer sends a discovery message through an IPv4 route using seg6 encap, while net.ipv6.seg6_flowlabel is set to 1. seg6_make_flowlabel() already has a net pointer, use skb_get_hash_net(). WARNING: net/core/flow_dissector.c:1131 at __skb_flow_dissect+0x910/0x5368 net/core/flow_dissector.c:1126, CPU#0: syz.0.17/4930 Call trace: __skb_flow_dissect+0x910/0x5368 net/core/flow_dissector.c:1126 (P) __skb_get_hash_net+0xe0/0x29c net/core/flow_dissector.c:1903 skb_get_hash include/linux/skbuff.h:1663 [inline] seg6_make_flowlabel+0xcc/0x1ec net/ipv6/seg6_iptunnel.c:132 __seg6_do_srh_encap+0x320/0xbf4 net/ipv6/seg6_iptunnel.c:161 seg6_do_srh+0x4b4/0xa44 net/ipv6/seg6_iptunnel.c:431 seg6_output_core+0x164/0x688 net/ipv6/seg6_iptunnel.c:681 seg6_output+0x44/0x1ac net/ipv6/seg6_iptunnel.c:744 lwtunnel_output+0x3d0/0x664 net/core/lwtunnel.c:356 dst_output include/net/dst.h:470 [inline] ip_local_out+0x110/0x148 net/ipv4/ip_output.c:131 iptunnel_xmit+0x50c/0xd38 net/ipv4/ip_tunnel_core.c:97 udp_tunnel_xmit_skb+0x220/0x348 net/ipv4/udp_tunnel_core.c:187 tipc_udp_xmit+0x75c/0x9c0 net/tipc/udp_media.c:202 tipc_udp_send_msg+0x214/0x374 net/tipc/udp_media.c:274 tipc_bearer_xmit_skb+0x260/0x3b0 net/tipc/bearer.c:576 tipc_enable_bearer net/tipc/bearer.c:366 [inline] __tipc_nl_bearer_enable+0xc90/0xfb0 net/tipc/bearer.c:1048 tipc_nl_bearer_enable+0x2c/0x48 net/tipc/bearer.c:1057 genl_family_rcv_msg_doit+0x1e4/0x2d4 net/netlink/genetlink.c:1114 Fixes: d58e468b1112 ("flow_dissector: implements flow dissector BPF hook") Reported-by: syzbot+9408fbe0e6452a12e9ab@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/6abac2eb.3654fce1.1bec97.0000.GAE@google.com/ Signed-off-by: Eric Dumazet <edumazet@kernel.org> Reviewed-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20260928194524.3617299-1-edumazet@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-09-30seg6: reallocate the skb head on L2 encapsulation only when neededYuya Kusakabe
The L2 encapsulation modes of the seg6 lwtunnel reallocate the skb head on every packet, where the IPv6 encapsulation modes reallocate only when they have to. Ask for the whole encapsulation up front instead, so that the reallocation happens at most once and only when the headroom really is too small: skb->mac_len + sizeof(struct ipv6hdr) + ipv6_optlen(tinfo->srh) + dst_dev_overhead(cache_dst, skb) __seg6_do_srh_encap() then finds the room it needs and its own skb_cow_head() becomes a no-op. Drivers reserve more than that on the forwarding path, so the reallocation usually disappears altogether. A single-segment policy on ixgbe needs 14 (mac_len) + 40 (ipv6hdr) + 24 (SRH) + 16 (LL_RESERVED_SPACE) = 94 against the 206 bytes the driver leaves. Where the headroom is smaller, as on a veth pair, pskb_expand_head() is called once per forwarded packet instead of twice. Asking only for skb->mac_len would still take two whenever the skb is header-cloned, because the cow that unclones it does not also make room for the outer header. The cost is amplified by CONFIG_INIT_ON_ALLOC_DEFAULT_ON, which many distributions enable: every new head is zeroed in full, and that memset alone accounts for 16% of the datapath profile. Throughput at 0.5% packet loss, 64-byte frames forwarded through one 2.30 GHz core (Xeon E5-2650 v3, ixgbe 82599ES), offered by TRex and binary-searched over 10 runs of 10 s: Before: 654.6 kpps After: 965.7 kpps Signed-off-by: Yuya Kusakabe <yuya.kusakabe@gmail.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn> Link: https://patch.msgid.link/20260925-seg6-l2cow-v3-1-fc83821542a7@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-09-29ipv6: update NUD_FAILED neighbors from NA messagesLawrence Lee
Transition a FAILED neighbor entry to STALE upon receipt of an NA message on routers when accept_untracked_na is enabled. This extends the RFC 9131 accept_untracked_na behavior so that FAILED entries are treated the same as non-existent entries. RFC 4861 section 7.3.3 says that an entry should be deleted when address resolution fails. Linux instead retains the entry in NUD_FAILED, so treating it as untracked is consistent with the protocol model. Trying to resolve FAILED neighbors via periodic probing (e.g. using NTF_EXT_MANAGED) is more work compared to this approach which uses information in NAs that the kernel may already be receiving. Note that because this behavior in IPv6 is dependent on the accept_untracked_na sysctl setting, this approach is more conservative than IPv4 which transitions FAILED neighbors to STALE by default upon receiving GARPs. Link: https://lore.kernel.org/r/20260813233344.445265-1-lfqlee314@gmail.com Signed-off-by: Lawrence Lee <lfqlee314@gmail.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/6be400e601f4ffa59e47ddb5daa33ecdd85dd88b.1790127207.git.lfqlee314@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-09-29net: gso: limit recursive IP-in-IP segmentationZihan Xi
IP-in-IP GSO can re-enter inet_gso_segment() or ipv6_gso_segment() for each nested IP header. encap_level tracks header bytes, not callback depth, so a deep chain can exhaust the kernel stack. Making inet_gso_segment() stackable introduced unbounded IPv4 nesting; IPIP GSO/TSO later made the path reachable. The IPv6 stackable path was introduced separately and uses the same guard. Count IPv4 and IPv6 GSO handler entries in skb_gso_cb, initialized once per top-level GSO operation and preserved across GRE/UDP context changes. Use the existing IP_TUNNEL_RECURSION_LIMIT for both handlers. The first five entries pass, and the sixth returns -EINVAL before dispatching another GSO callback. Fixes: 3347c9602955 ("ipv4: gso: make inet_gso_segment() stackable") Cc: stable@vger.kernel.org Reported-by: Vega <vega@nebusec.ai> Closes: https://lore.kernel.org/all/cover.1790157745.git.zihanx@nebusec.ai/ Assisted-by: LLM Co-developed-by: Luxing Yin <root@tr0jan.top> Signed-off-by: Luxing Yin <root@tr0jan.top> Signed-off-by: Zihan Xi <zihanx@nebusec.ai> Reviewed-by: Willem de Bruijn <willemb@google.com> Link: https://patch.msgid.link/20260924051521.32568-2-zihanx@nebusec.ai Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-09-28ipv6: Remove FIB6_EXCEPTION_BUCKET_FLUSHED.Kuniyuki Iwashima
The FIB6_EXCEPTION_BUCKET_FLUSHED logic has been dead since added. Commit 0346ec2f080b ("ipv6: Prevent rt6_insert_exception() for dying fib6_info.") restored the original race protection in rt6_insert_exception() by reusing fib6_info.fib6_destroying. The flag now prevents two races for per-cpu and exception routes. Let's remove FIB6_EXCEPTION_BUCKET_FLUSHED and set fib6_destroying in fib6_purge_rt(). Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20260926033355.3295550-1-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-09-28seg6: ensure packet data is writable before modifying SRH and IPv6 DAAndrea Mayer
advance_nextseg() modifies the SRH Segments Left field and the IPv6 destination address without ensuring the packet data is writable. seg6_next_csid_advance_arg() has the same problem when it advances the NEXT-C-SID argument in the destination address. The skb may be cloned, for example by an AF_PACKET socket receiving on the ingress device. advance_nextseg() and seg6_next_csid_advance_arg() then write into the packet data shared with the clone. A read from that socket can return the modified packet instead of the received one. The simplified path below shows this for advance_nextseg(): __netif_receive_skb_one_core __netif_receive_skb_core deliver_skb [orig: users=2, cloned=0] packet_rcv skb_clone clone queued to the AF_PACKET socket consume_skb(orig) [orig: users=1, cloned=1] ipv6_rcv ip6_rcv_core skb_share_check: no-op [orig: users=1] [...] input_action_end_core advance_nextseg writes into the data shared with the clone Call skb_ensure_writable() in advance_nextseg() and in seg6_next_csid_advance_arg() before they modify the packet data. skb_ensure_writable() may reallocate skb->head, which invalidates the pointers into the packet data taken before the call. advance_nextseg() now returns a valid SRH pointer, or NULL if skb_ensure_writable() fails. seg6_next_csid_advance_arg() takes the pointer to the destination address from the skb after skb_ensure_writable(). On failure, the callers drop the packet with SKB_DROP_REASON_NOMEM. Fixes: 140f04c33bbc ("ipv6: sr: implement several seg6local actions") Fixes: 848f3c0d4769 ("seg6: add NEXT-C-SID support for SRv6 End behavior") Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it> Link: https://patch.msgid.link/20260925133807.32-1-andrea.mayer@uniroma2.it Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-09-25ipv6: fix prefix route expiry in modify_prefix_route()Qishuai Liu
modify_prefix_route() is given the lifetime in clock_t relative to now, but fib6_set_expires() wants an absolute jiffies value. So when a permanent address is changed to a finite valid_lft, the prefix route ends up already expired and GC removes it. Steps to reproduce: ip link add dummy9 type dummy ip link set dummy9 up ip -6 addr add 2001:db8:9::1/64 dev dummy9 ip -6 addr change 2001:db8:9::1/64 dev dummy9 valid_lft 3600 preferred_lft 3600 ip -6 route show dev dummy9 # expires is negative Fixes: 8308f3ff1753 ("net/ipv6: Add support for specifying metric of connected routes") Signed-off-by: Qishuai Liu <lqs@lqs.me> Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20260923132048.3272878-1-lqs@lqs.me Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-09-24Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/netJakub Kicinski
Cross-merge networking fixes after downstream PR (net-7.3-rc5). Conflicts: drivers/net/mdio/mdio-realtek-rtl9300.c 89a8a1eef2d44 ("net: mdio: realtek-rtl9300: fix RTL931x C22 extended page selection") cc3cb8db1eef9 ("net: mdio: realtek-rtl9300: Add page tracking") https://lore.kernel.org/arUZOqy73bE2pp0w@sirena.org.uk net/8021q/vlan_dev.c cd5dd68267c4 ("vlan: ensure sufficient headroom in vlan_dev_hard_header()") ca6ff8dd70eb ("vlan: annotate data-races in vlan_dev_priv fields") Adjacent changes: net/ipv6/ip6_gre.c dd47bcf279f1 ("ip6_gre: Call ip6erspan_tunnel_unlink_md() in ip6erspan_changelink().") cce829e2aa1d ("ip6_gre: Protect ip6gre_net.tunnels[][] with mutex.") drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b5d9e9d4d0c1 ("eth: fbnic: use the Rx queue napi pointer to find the napi vector") c0aca269ec07 ("eth: fbnic: Make Rx completion coalescing configurable") drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c d68acbf93531 ("net: stmmac: selftests: Support running selftests on DSA conduits") 85ca3292d7a3 ("net: stmmac: Remove ARP offload code") drivers/net/ethernet/wangxun/libwx/wx_hw.c 3173cba11701 ("net: libwx: fix races in Tx timestamp handling") 7042c8c193e5 ("net: libwx: rename wx_pf_flags to wx_flags") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-09-23ipv6: sr: enforce exact attribute length for SEG6_ATTR_DSTHui Peng
In seg6_genl_policy, SEG6_ATTR_DST is defined with .type = NLA_BINARY and .len = sizeof(struct in6_addr). For NLA_BINARY, .len only enforces the maximum payload length and permits shorter payloads (e.g., 0 bytes). When seg6_genl_set_tunsrc() copies sizeof(struct in6_addr) bytes via kmemdup(val, sizeof(*val), GFP_KERNEL), a short SEG6_ATTR_DST attribute triggers a 16-byte out-of-bounds read past skb->tail into uninitialized skb->head memory, which is stored in sdata->tun_src and leaked back to userspace via SEG6_CMD_GET_TUNSRC. Switch SEG6_ATTR_DST in seg6_genl_policy to NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)) so that generic netlink validation rejects any attribute whose length is not exactly sizeof(struct in6_addr) with -ERANGE. Tested in QEMU against Linux 7.3.0-rc3 by sending a SEG6_CMD_SET_TUNSRC Generic Netlink message with a 0-byte SEG6_ATTR_DST attribute followed by SEG6_CMD_GET_TUNSRC. On the unfixed kernel, SEG6_CMD_SET_TUNSRC succeeds (err = 0) and SEG6_CMD_GET_TUNSRC leaks 16 bytes of uninitialized kernel heap memory (tun_src = 836a61ecc4d25a1042a8d60411cfb378); with this patch applied, SEG6_CMD_SET_TUNSRC is rejected by netlink policy validation with -ERANGE (-34) and tun_src remains zeroed. Fixes: 915d7e5e5930 ("ipv6: sr: add code base for control plane support of SR-IPv6") Cc: stable@vger.kernel.org Signed-off-by: Hui Peng <benquike@gmail.com> Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn> Reviewed-by: Justin Iurman <justin.iurman@gmail.com> Reviewed-by: Andrea Mayer <andrea.mayer@uniroma2.it> Link: https://patch.msgid.link/20260921044025.1535982-1-benquike@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-09-21ipv6: Fix dst leak for uncached routes.Kuniyuki Iwashima
ip6_route_output_flags(), ip6_rt_put_flags(), and ip6_dst_check() detect an uncached route by list_empty(&rt->dst.rt_uncached), which replaced the static DST_NOCACHE flag check in commit a4c2fd7f7891 ("net: remove DST_NOCACHE flag"). When a device is unregistered, rt6_uncached_list_flush_dev() unlinks uncached routes tied to the device from rt6_uncached_list. Previously, they were moved to another list with list_move() (__list_del_entry() + list_add()), and since commit 98aa546af5e4 ("inet: remove (struct uncached_list)->quarantine"), the routes are just unlinked with list_del_init(). If list_del_init() runs concurrently, list_empty() evaluates to true; ip6_route_output_flags() calls dst_hold_safe() incorrectly and ip6_rt_put_flags() skips ip6_rt_put(), leaking dst, and thus dev tied via rt->from as well. The same race is partially fixed by commit 9a6f0c4d5796 ("dst: fix races in rt6_uncached_list_del() and rt_del_uncached_list()"). Let's check rt6->dst.rt_uncached_list instead. Note that IPv4 does not have the same issue. Fixes: 98aa546af5e4 ("inet: remove (struct uncached_list)->quarantine") Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn> Reviewed-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260920191558.2990636-1-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-09-21ipv6: Prevent rt6_insert_exception() for dying fib6_info.Kuniyuki Iwashima
Before the cited commit, fib6_nh_flush_exceptions() always set from->exception_bucket_flushed = 1 under rt6_exception_lock to prevent rt6_insert_exception() from inserting a new exception for a dying fib6_info. The flag was replaced with the FIB6_EXCEPTION_BUCKET_FLUSHED bit stored in nh->rt6i_exception_bucket. The problem is that now the bit is only set when the bucket is not NULL and fib6_nh_flush_exceptions() is called from fib6_nh_release() after fib6_ref has already reached zero. If rt6_insert_exception() is called while the target fib6_info is being removed via fib6_purge_rt(), a new exception could be created successfully because rt6_flush_exceptions() no longer sets the bit. This creates a reference cycle between the fib6_info and the exception route, leaking the fib6_info, its nexthop device, and all per-CPU routes in fib6_nh->rt6i_pcpu, which stalls netdev unregistration. [ 34.680602] unregister_netdevice: waiting for gre6 to become free. Usage count = 68 [ 44.920675] unregister_netdevice: waiting for gre6 to become free. Usage count = 68 [ 55.176582] unregister_netdevice: waiting for gre6 to become free. Usage count = 68 Let's call fib6_drop_pcpu_from() before rt6_flush_exceptions(), to set fib6_destroying before rt6_exception_lock, and check f6i->fib6_destroying in rt6_insert_exception(). Note that FIB6_EXCEPTION_BUCKET_FLUSHED logic is dead and we can clean it up in net-next. Fixes: cc5c073a693f ("ipv6: Move exception bucket to fib6_nh") Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20260918082209.2853582-1-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-09-21Merge tag 'nf-26-09-18' of ↵Jakub Kicinski
git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf Pablo Neira Ayuso says: ==================== Netfilter/IPVS fixes for net The following patchset contains Netfilter/IPVS fixes for net, they are: 1) Set on HW_DEAD after HW_PENDING is cleared in the flowtable offload to ensure GC does not zap it, from Jérémy Jean. 2) Hold the nfnetlink_queue mutex while removing the queue instance from the netlink notifier that handles NETLINK_URELEASE to fix a possible race with the UNBIND command. From Florian Westphal. 3) Reject route with NULL rt6i_idev in ip6t_rpfilter. From Weiming Shi. 4) Reject rtinfo->addrnr set to zero from ip6t_rt .checkentry path. This also fortifies the datapath loop as per Florian's request. From Luxiao Xu. 5) Fix checksuming in nft_synproxy for IPv6, from Karl Mehltretter. 6) Revalidate ihl before calling icmp_send() in IPVS, from Julian Anastasov. 7) Fix suspicious RCU usage splat in ctnetlink with expectations. 8) Check for expired catchall elements in the insert and deactivate path. From Aohan Mei. * tag 'nf-26-09-18' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: nf_tables: skip expired catchall elements on insert and delete netfilter: ctnetlink: fix suspicious RCU usage in expect_iter_name ipvs: revalidate ihl before icmp_send netfilter: nft_synproxy: use the family-aware checksum helper netfilter: ip6t_rt: fix zero-address non-strict match out-of-bounds read netfilter: ip6t_rpfilter: reject routes without inet6_dev netfilter: nfnetlink_queue: hold nfnl mutex in event notifier netfilter: flowtable: publish HW_DEAD after worker is done ==================== Link: https://patch.msgid.link/20260918112844.194503-1-pablo@netfilter.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>