<feed xmlns='http://www.w3.org/2005/Atom'>
<title>laptop-kernel/net/ipv6, branch master</title>
<subtitle>Linux kernel tree for laptop</subtitle>
<id>https://git.zx2c4.com/laptop-kernel/atom/net/ipv6?h=master</id>
<link rel='self' href='https://git.zx2c4.com/laptop-kernel/atom/net/ipv6?h=master'/>
<link rel='alternate' type='text/html' href='https://git.zx2c4.com/laptop-kernel/'/>
<updated>2026-10-15T10:50:03Z</updated>
<entry>
<title>calipso: keep BIG TCP payload_len in calipso_skbuff_setattr()</title>
<updated>2026-10-15T10:50:03Z</updated>
<author>
<name>Joas Antonio dos Santos</name>
<email>joasantonio108@gmail.com</email>
</author>
<published>2026-10-09T15:59:19Z</published>
<link rel='alternate' type='text/html' href='https://git.zx2c4.com/laptop-kernel/commit/?id=8070ed578b6b9134e045627fb745c887a806d46e'/>
<id>urn:sha1:8070ed578b6b9134e045627fb745c887a806d46e</id>
<content type='text'>
calipso_skbuff_setattr() adjusts payload_len by the length of the
option it inserts or resizes:

	payload = ntohs(ip6_hdr-&gt;payload_len);
	ip6_hdr-&gt;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-&gt;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-&gt;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-&gt;data, so skb-&gt;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 &lt;edumazet@kernel.org&gt;
Suggested-by: Wang Zhan &lt;wang.zhan@smartx.com&gt;
Signed-off-by: Joas Antonio dos Santos &lt;joasantonio108@gmail.com&gt;
Assisted-by: Claude:claude-opus-5-5
Reviewed-by: Wang Zhan &lt;wang.zhan@smartx.com&gt;
Acked-by: Paul Moore &lt;paul@paul-moore.com&gt;
Link: https://patch.msgid.link/179156155963.36253.400481753322266658@gmail.com
Signed-off-by: Paolo Abeni &lt;pabeni@redhat.com&gt;
</content>
</entry>
<entry>
<title>ipv6: do not warn on route notification size race</title>
<updated>2026-10-08T18:32:36Z</updated>
<author>
<name>Daehyeon Ko</name>
<email>4ncienth@gmail.com</email>
</author>
<published>2026-10-08T05:29:23Z</published>
<link rel='alternate' type='text/html' href='https://git.zx2c4.com/laptop-kernel/commit/?id=c97426ec649d99596d8969e1a052c16b14b7b485'/>
<id>urn:sha1:c97426ec649d99596d8969e1a052c16b14b7b485</id>
<content type='text'>
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 &lt;idosch@nvidia.com&gt;
Link: https://lore.kernel.org/netdev/20261007114003.GA1011260@shredder/
Suggested-by: Ido Schimmel &lt;idosch@nvidia.com&gt;
Cc: stable@vger.kernel.org
Signed-off-by: Daehyeon Ko &lt;4ncienth@gmail.com&gt;
Link: https://patch.msgid.link/4012604727e5ba80b69ccd4d08796511397ddaef.1791423190.git.4ncienth@gmail.com
Signed-off-by: Jakub Kicinski &lt;kuba@kernel.org&gt;
</content>
</entry>
<entry>
<title>ip6_gre: remove obsolete ERSPAN PMTU update</title>
<updated>2026-10-06T23:07:29Z</updated>
<author>
<name>Daehyeon Ko</name>
<email>4ncienth@gmail.com</email>
</author>
<published>2026-10-02T03:30:58Z</published>
<link rel='alternate' type='text/html' href='https://git.zx2c4.com/laptop-kernel/commit/?id=8bc60db48e8cba35488bbd6e1f94aa990afa275a'/>
<id>urn:sha1:8bc60db48e8cba35488bbd6e1f94aa990afa275a</id>
<content type='text'>
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)-&gt;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 &lt;idosch@nvidia.com&gt;
Signed-off-by: Daehyeon Ko &lt;4ncienth@gmail.com&gt;
Reviewed-by: Ido Schimmel &lt;idosch@nvidia.com&gt;
Link: https://patch.msgid.link/20261002033058.358137-1-4ncienth@gmail.com
Signed-off-by: Jakub Kicinski &lt;kuba@kernel.org&gt;
</content>
</entry>
<entry>
<title>ipv6: sr: use skb_get_hash_net() in seg6_make_flowlabel()</title>
<updated>2026-10-01T00:37:47Z</updated>
<author>
<name>Eric Dumazet</name>
<email>edumazet@kernel.org</email>
</author>
<published>2026-09-28T19:45:24Z</published>
<link rel='alternate' type='text/html' href='https://git.zx2c4.com/laptop-kernel/commit/?id=8ec454dcd00ce3375119111c6394964455b36d0d'/>
<id>urn:sha1:8ec454dcd00ce3375119111c6394964455b36d0d</id>
<content type='text'>
Since commit d58e468b1112 ("flow_dissector: implements flow dissector
BPF hook") __skb_flow_dissect() needs a net pointer, either from
skb-&gt;dev, skb-&gt;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-&gt;dev nor skb-&gt;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 &lt;edumazet@kernel.org&gt;
Reviewed-by: Xuanqiang Luo &lt;luoxuanqiang@kylinos.cn&gt;
Reviewed-by: Ido Schimmel &lt;idosch@nvidia.com&gt;
Link: https://patch.msgid.link/20260928194524.3617299-1-edumazet@kernel.org
Signed-off-by: Jakub Kicinski &lt;kuba@kernel.org&gt;
</content>
</entry>
<entry>
<title>net: gso: limit recursive IP-in-IP segmentation</title>
<updated>2026-09-29T10:02:37Z</updated>
<author>
<name>Zihan Xi</name>
<email>zihanx@nebusec.ai</email>
</author>
<published>2026-09-24T05:15:21Z</published>
<link rel='alternate' type='text/html' href='https://git.zx2c4.com/laptop-kernel/commit/?id=006c8b834aed8b02bd8fb9fb05e9e7ead37d1763'/>
<id>urn:sha1:006c8b834aed8b02bd8fb9fb05e9e7ead37d1763</id>
<content type='text'>
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 &lt;vega@nebusec.ai&gt;
Closes: https://lore.kernel.org/all/cover.1790157745.git.zihanx@nebusec.ai/
Assisted-by: LLM
Co-developed-by: Luxing Yin &lt;root@tr0jan.top&gt;
Signed-off-by: Luxing Yin &lt;root@tr0jan.top&gt;
Signed-off-by: Zihan Xi &lt;zihanx@nebusec.ai&gt;
Reviewed-by: Willem de Bruijn &lt;willemb@google.com&gt;
Link: https://patch.msgid.link/20260924051521.32568-2-zihanx@nebusec.ai
Signed-off-by: Paolo Abeni &lt;pabeni@redhat.com&gt;
</content>
</entry>
<entry>
<title>seg6: ensure packet data is writable before modifying SRH and IPv6 DA</title>
<updated>2026-09-29T02:19:48Z</updated>
<author>
<name>Andrea Mayer</name>
<email>andrea.mayer@uniroma2.it</email>
</author>
<published>2026-09-25T13:38:07Z</published>
<link rel='alternate' type='text/html' href='https://git.zx2c4.com/laptop-kernel/commit/?id=8ae3f4067ba4ae3a15581392f6dac422e3d3def0'/>
<id>urn:sha1:8ae3f4067ba4ae3a15581392f6dac422e3d3def0</id>
<content type='text'>
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-&gt;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 &lt;andrea.mayer@uniroma2.it&gt;
Link: https://patch.msgid.link/20260925133807.32-1-andrea.mayer@uniroma2.it
Signed-off-by: Jakub Kicinski &lt;kuba@kernel.org&gt;
</content>
</entry>
<entry>
<title>ipv6: fix prefix route expiry in modify_prefix_route()</title>
<updated>2026-09-26T00:34:11Z</updated>
<author>
<name>Qishuai Liu</name>
<email>lqs@lqs.me</email>
</author>
<published>2026-09-23T13:20:48Z</published>
<link rel='alternate' type='text/html' href='https://git.zx2c4.com/laptop-kernel/commit/?id=a7bfaba4823e3c165bb2004c74eff7c096672bc7'/>
<id>urn:sha1:a7bfaba4823e3c165bb2004c74eff7c096672bc7</id>
<content type='text'>
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 &lt;lqs@lqs.me&gt;
Reviewed-by: Hangbin Liu &lt;liuhangbin@kylinos.cn&gt;
Reviewed-by: Ido Schimmel &lt;idosch@nvidia.com&gt;
Link: https://patch.msgid.link/20260923132048.3272878-1-lqs@lqs.me
Signed-off-by: Jakub Kicinski &lt;kuba@kernel.org&gt;
</content>
</entry>
<entry>
<title>ipv6: sr: enforce exact attribute length for SEG6_ATTR_DST</title>
<updated>2026-09-24T01:34:13Z</updated>
<author>
<name>Hui Peng</name>
<email>benquike@gmail.com</email>
</author>
<published>2026-09-21T04:40:25Z</published>
<link rel='alternate' type='text/html' href='https://git.zx2c4.com/laptop-kernel/commit/?id=2d959c75c27f90e9ec489d18ce5ee6b852ad4741'/>
<id>urn:sha1:2d959c75c27f90e9ec489d18ce5ee6b852ad4741</id>
<content type='text'>
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-&gt;tail into uninitialized
skb-&gt;head memory, which is stored in sdata-&gt;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 &lt;benquike@gmail.com&gt;
Reviewed-by: Hangbin Liu &lt;liuhangbin@kylinos.cn&gt;
Reviewed-by: Justin Iurman &lt;justin.iurman@gmail.com&gt;
Reviewed-by: Andrea Mayer &lt;andrea.mayer@uniroma2.it&gt;
Link: https://patch.msgid.link/20260921044025.1535982-1-benquike@gmail.com
Signed-off-by: Jakub Kicinski &lt;kuba@kernel.org&gt;
</content>
</entry>
<entry>
<title>ipv6: Fix dst leak for uncached routes.</title>
<updated>2026-09-22T01:12:42Z</updated>
<author>
<name>Kuniyuki Iwashima</name>
<email>kuniyu@google.com</email>
</author>
<published>2026-09-20T19:14:32Z</published>
<link rel='alternate' type='text/html' href='https://git.zx2c4.com/laptop-kernel/commit/?id=be31fe6333f534155e6b408f1ef6d77974bb41aa'/>
<id>urn:sha1:be31fe6333f534155e6b408f1ef6d77974bb41aa</id>
<content type='text'>
ip6_route_output_flags(), ip6_rt_put_flags(), and ip6_dst_check()
detect an uncached route by list_empty(&amp;rt-&gt;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)-&gt;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-&gt;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-&gt;dst.rt_uncached_list instead.

Note that IPv4 does not have the same issue.

Fixes: 98aa546af5e4 ("inet: remove (struct uncached_list)-&gt;quarantine")
Signed-off-by: Kuniyuki Iwashima &lt;kuniyu@google.com&gt;
Reviewed-by: Hangbin Liu &lt;liuhangbin@kylinos.cn&gt;
Reviewed-by: Xuanqiang Luo &lt;luoxuanqiang@kylinos.cn&gt;
Reviewed-by: Ido Schimmel &lt;idosch@nvidia.com&gt;
Reviewed-by: Eric Dumazet &lt;edumazet@google.com&gt;
Link: https://patch.msgid.link/20260920191558.2990636-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski &lt;kuba@kernel.org&gt;
</content>
</entry>
<entry>
<title>ipv6: Prevent rt6_insert_exception() for dying fib6_info.</title>
<updated>2026-09-21T23:20:00Z</updated>
<author>
<name>Kuniyuki Iwashima</name>
<email>kuniyu@google.com</email>
</author>
<published>2026-09-18T08:22:05Z</published>
<link rel='alternate' type='text/html' href='https://git.zx2c4.com/laptop-kernel/commit/?id=0346ec2f080b40d95ed05b853bb9226289e75212'/>
<id>urn:sha1:0346ec2f080b40d95ed05b853bb9226289e75212</id>
<content type='text'>
Before the cited commit, fib6_nh_flush_exceptions() always set
from-&gt;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-&gt;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-&gt;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-&gt;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 &lt;kuniyu@google.com&gt;
Reviewed-by: Ido Schimmel &lt;idosch@nvidia.com&gt;
Link: https://patch.msgid.link/20260918082209.2853582-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski &lt;kuba@kernel.org&gt;
</content>
</entry>
</feed>
