summaryrefslogtreecommitdiff
path: root/net
AgeCommit message (Collapse)Author
2026-06-30netfilter: nft_fib: reject fib expression on the netdev egress hookTheodor Arsenij Larionov-Trichkine
A fib expression in a netdev egress base chain dereferences nft_in(pkt), NULL on the transmit path, causing a NULL pointer dereference at eval. nft_fib_validate() masks the hook with NF_INET_* values, but netdev hook numbers are a separate enum that aliases them (NF_NETDEV_EGRESS == NF_INET_LOCAL_IN), so an egress chain passes validation and then faults. Add nft_fib_netdev_validate() that limits each result/flag to the netdev hook where the device it reads exists: the input-device cases (OIF, OIFNAME, ADDRTYPE with F_IIF) to ingress, the output-device case (ADDRTYPE with F_OIF) to egress, ADDRTYPE with no device flag to both. Also restrict nft_fib_validate() to NFPROTO_IPV4/IPV6/INET so its NF_INET_* masks are not applied to another family's hooks. Fixes: 42df6e1d221d ("netfilter: Introduce egress hook") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/netfilter-devel/ajxsjcDOnwllMfoR@strlen.de/ Signed-off-by: Theodor Arsenij Larionov-Trichkine <theodorlarionov@gmail.com> Signed-off-by: Florian Westphal <fw@strlen.de>
2026-06-30netfilter: nfnetlink_cthelper: cap to maximum number of expectation per masterPablo Neira Ayuso
If userspace helper policy updates sets maximum number of expectation to zero, cap it to NF_CT_EXPECT_MAX_CNT (255) on updates too. Fixes: 397c8300972f ("netfilter: nf_conntrack_helper: cap maximum number of expectation at helper registration") Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Florian Westphal <fw@strlen.de>
2026-06-30netfilter: nf_conntrack_sip: validate skb_dst() before accessing itPablo Neira Ayuso
tc ingress and openvswitch do not guarantee routing information to be available. These subsystems use the conntrack helper infrastructure, and the SIP helper relies on the skb_dst() to be present if sip_external_media is set to 1 (which is disabled by default as a module parameter). This effectively disables the sip_external_media toggle for these subsystems without resulting in a crash. Fixes: cae3a2627520 ("openvswitch: Allow attaching helpers to ct action") Fixes: b57dc7c13ea9 ("net/sched: Introduce action ct") Cc: stable@vger.kernel.org Reported-by: Ren Wei <n05ec@lzu.edu.cn> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Florian Westphal <fw@strlen.de>
2026-06-30netfilter: ipset: fix race between dump and ip_set_list resizeXiang Mei
The release path of ip_set_dump_do() and ip_set_dump_done() read inst->ip_set_list via ip_set_ref_netlink(), a plain rcu_dereference_raw() of the array pointer. These run from netlink_recvmsg() without the nfnl mutex and without an RCU read-side critical section. A concurrent ip_set_create() can grow the array: it publishes the new array, calls synchronize_net() and then kvfree()s the old one. Since the dump paths read the array outside any RCU reader, synchronize_net() does not wait for them and the old array can be freed while they still index into it, causing a use-after-free. The dumped set itself stays pinned via set->ref_netlink, so only the array load needs protecting. Take rcu_read_lock() around it, matching ip_set_get_byname() and __ip_set_put_byindex(). BUG: KASAN: slab-use-after-free in ip_set_dump_do (net/netfilter/ipset/ip_set_core.c:1697) Read of size 8 at addr ffff88800b5c4018 by task exploit/150 Call Trace: ... kasan_report (mm/kasan/report.c:595) ip_set_dump_do (net/netfilter/ipset/ip_set_core.c:1697) netlink_dump (net/netlink/af_netlink.c:2325) netlink_recvmsg (net/netlink/af_netlink.c:1976) sock_recvmsg (net/socket.c:1159) __sys_recvfrom (net/socket.c:2315) ... Oops: general protection fault, probably for non-canonical address ... KASAN NOPTI KASAN: maybe wild-memory-access in range [0x02d6...d0-0x02d6...d7] RIP: 0010:ip_set_dump_do (net/netfilter/ipset/ip_set_core.c:1698) Kernel panic - not syncing: Fatal exception Fixes: 8a02bdd50b2e ("netfilter: ipset: Fix calling ip_set() macro at dumping") Cc: stable@vger.kernel.org Reported-by: Weiming Shi <bestswngs@gmail.com> Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Xiang Mei <xmei5@asu.edu> Acked-by: Jozsef Kadlecsik <kadlec@netfilter.org> Signed-off-by: Florian Westphal <fw@strlen.de>
2026-06-30netfilter: nft_set_pipapo: don't leak bad clone into future transactionFlorian Westphal
On memory allocation failure the cloned nft_pipapo_match can enter a bad state: - some fields can have their lookup tables resized while others did not - bits might have been toggled - scratch map can be undersized which also means m->bsize_max can be lower than what is required This means that the next insertion in the same batch can trigger out-of-bounds writes. Furthermore, a failure in the first can result in the bad clone to leak into the next transaction because the abort callback is never executed in this case (the upper layer saw an error and no attempt to allocate a transactional request was made). Record a state for the nft_pipapo_match structure: - NEW (pristine clone) - MOD (modified clone with good state) - ERR (potentially bogus content) Then make it so that deletes and insertions fail when the clone entered ERR state. In case the very first insert attempt results in an error, free the clone right away. Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges") Cc: stable@vger.kernel.org Reported-and-tested-by: Seesee <cjc000013@gmail.com> Reviewed-by: Stefano Brivio <sbrivio@redhat.com> Signed-off-by: Florian Westphal <fw@strlen.de>
2026-06-30netfilter: nf_conntrack_expect: zero at allocation timeFlorian Westphal
There are occasional LLM hints wrt. leaking uninitialized data to userspace via ctnetlink. Just zero at allocation time, expectations are not frequently used these days. Intentionally keeps _init as-is because we could theoretically support re-init, so add the missing exp->dir there. Signed-off-by: Florian Westphal <fw@strlen.de>
2026-06-29ipv6: fib6: fix NULL deref in fib6_walk_continue() on multi-batch dumpPengfei Zhang
inet6_dump_fib() saves its progress in cb->args[1] as a positional index within the current hash chain. Between batches, a concurrent fib6_new_table() can insert a new table at the chain head, shifting all existing entries. The saved index then lands on a different table, causing fib6_dump_table() to set w->root to the wrong table while w->node still points into the previous one. fib6_walk_continue() dereferences w->node->parent (NULL) and panics: BUG: kernel NULL pointer dereference, address: 0000000000000008 RIP: 0010:fib6_walk_continue+0x6e/0x170 Call Trace: <TASK> fib6_dump_table.isra.0+0xc5/0x240 inet6_dump_fib+0xf6/0x420 rtnl_dumpit+0x30/0xa0 netlink_dump+0x15b/0x460 netlink_recvmsg+0x1d6/0x2a0 ____sys_recvmsg+0x17a/0x190 Fix by storing tb->tb6_id in cb->args[1] instead of a positional index. On resume, skip entries until the id matches; a concurrent head-insert can never match the saved id, so the walker always resumes on the correct table. Fixes: 1b43af5480c3 ("[IPV6]: Increase number of possible routing tables to 2^32") Signed-off-by: Pengfei Zhang <zhangfeionline@gmail.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20260625070517.965597-1-zhangfeionline@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-29tcp: Decrement tcp_md5_needed static branchDmitry Safonov
In case of early freeing an unwanted TCP-MD5 key on TCP-AO connect(), md5sig_info is freed right away (and set to NULL). Later, at the moment of socket destruction, the static branch counter is not getting decremented. Add a missing decrement for TCP-MD5 static branch. Reported-by: Qihang <q.h.hack.winter@gmail.com> Fixes: 0aadc73995d0 ("net/tcp: Prevent TCP-MD5 with TCP-AO being set") Cc: stable@vger.kernel.org Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> Link: https://patch.msgid.link/20260625-tcp-md5-connect-v3-3-1fd313d6c1e0@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-29tcp: defer md5sig_info kfree past RCU grace period in tcp_connectMichael Bommarito
The md5+ao reconciliation in tcp_connect() (net/ipv4/tcp_output.c) has two symmetric branches: if (needs_md5) { tcp_ao_destroy_sock(sk, false); } else if (needs_ao) { tcp_clear_md5_list(sk); kfree(rcu_replace_pointer(tp->md5sig_info, NULL, ...)); } Both branches free a per-socket auth-info object while the socket is in TCP_SYN_SENT and is already on the inet ehash (inserted by inet_hash_connect() in tcp_v4_connect()). Both branches are reachable by softirq RX-path readers that load the corresponding info pointer via implicit RCU before bh_lock_sock_nested() is taken. The needs_md5 branch is fixed in the prior patch by re-introducing the call_rcu() free in tcp_ao_destroy_sock(): the equivalent per-key loop runs inside tcp_ao_info_free_rcu(), the RCU callback, so by the time it frees each tcp_ao_key all softirq readers that captured the container have already completed rcu_read_unlock(). The needs_ao branch is not symmetric in the same way. The container free can be deferred via kfree_rcu(md5sig, rcu) -- struct tcp_md5sig_info already has the required rcu member (include/net/tcp.h:1999-2002), and the rest of the tree already does this in the tcp_md5sig_info_add() rollback paths (net/ipv4/tcp_ipv4.c:1410, 1436). But the per-key teardown is done by tcp_clear_md5_list() in process context BEFORE the container's RCU grace period: it walks &md5sig->head and frees each tcp_md5sig_key with bare hlist_del + kfree. A concurrent softirq reader in __tcp_md5_do_lookup() / __tcp_md5_do_lookup_exact() (tcp_ipv4.c:1253, 1298) walks the same list via hlist_for_each_entry_rcu() and races with that bare kfree on the keys themselves -- a per-key slab use-after-free of the same class as the TCP-AO bug, on the same race window. Fix this in two halves: 1. Convert the bare kfree() in tcp_connect() to kfree_rcu() so the md5sig_info container joins the rest of the md5sig lifecycle. The local-variable lift is mechanical and required because kfree_rcu() is a macro that expects an lvalue. 2. Make tcp_clear_md5_list() RCU-safe by replacing hlist_del + kfree(key) with hlist_del_rcu + kfree_rcu(key, rcu). struct tcp_md5sig_key already carries the rcu member (include/net/tcp.h:1995) and tcp_md5_do_del() (net/ipv4/tcp_ipv4.c:1456) already uses kfree_rcu, so this restores the lifecycle invariant the rest of the file follows rather than introducing a one-off. The other caller of tcp_clear_md5_list() is tcp_md5_destruct_sock() (net/ipv4/tcp.c:412), which runs from the sock destructor when the socket is already unhashed and unreachable; the extra grace period there is unnecessary but harmless. Making the helper unconditionally RCU-safe is the cleaner contract. The needs_ao branch is not reachable by the userns reproducer used to demonstrate the AO-side splat (the repro installs both keys but ends up in the needs_md5 branch because the connect peer matches the MD5 key, not the AO key); however the symmetric race exists and a maintainer touching this code should not have to think about which branch escapes RCU and which one does not. Fixes: 51e547e8c89c ("tcp: Free TCP-AO/TCP-MD5 info/keys without RCU") Cc: stable@vger.kernel.org # v6.18+ Suggested-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> Reviewed-by: Dmitry Safonov <dima@arista.com> Reviewed-by: Eric Dumazet <edumazet@google.com> [also credits to Qihang, who found that this races with tcp-diag] Reported-by: Qihang <q.h.hack.winter@gmail.com> Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> Link: https://patch.msgid.link/20260625-tcp-md5-connect-v3-2-1fd313d6c1e0@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-29tcp: restore RCU grace period in tcp_ao_destroy_sockMichael Bommarito
Commit 51e547e8c89c ("tcp: Free TCP-AO/TCP-MD5 info/keys without RCU") removed the call_rcu() callback from tcp_ao_destroy_sock(), arguing that "the destruction of info/keys is delayed until the socket destructor" and therefore "no one can discover it anymore". That argument does not hold for the call site in tcp_connect() (net/ipv4/tcp_output.c:4327-4332). At that point the socket is in TCP_SYN_SENT, has already been inserted into the inet ehash by inet_hash_connect() in tcp_v4_connect(), and is therefore very much discoverable: any softirq running tcp_v4_rcv() on another CPU can take the socket out of the ehash, walk into tcp_inbound_hash(), and load tp->ao_info via implicit RCU before bh_lock_sock_nested() is taken on the destroying CPU. The reader path then enters __tcp_ao_do_lookup() (net/ipv4/tcp_ao.c:208) which re-loads tp->ao_info via rcu_dereference_check(); the re-load can still observe the (about-to-be-freed) pointer because there is no synchronize_rcu() between rcu_assign_pointer(tp->ao_info, NULL) and tcp_ao_info_free() in tcp_ao_destroy_sock(). The captured pointer is then walked at line 223: hlist_for_each_entry_rcu(key, &ao->head, node, ...) The writer's synchronous kfree() is free to complete between the line 218 re-fetch and the line 223 hlist iteration. The slab is reused (or simply LIST_POISON1-stamped if not yet reused) and the iteration walks attacker-controlled or poison memory in softirq context. Reproducer (no debug shim, stock x86_64 v7.1-rc2 SMP+KASAN, QEMU+KVM): an unprivileged uid=1000 process inside CLONE_NEWUSER|CLONE_NEWNET installs TCP_MD5SIG + TCP_AO_ADD_KEY on a TCP socket, sprays forged TCP-AO segments toward its eventual 4-tuple via raw sockets, then calls connect(). The md5-wins reconciliation in tcp_connect() fires tcp_ao_destroy_sock(); the softirq backlog reader on the loopback NAPI path crashes on the freed ao->head.first walk: Oops: general protection fault, probably for non-canonical address 0xfbd59c000000002f KASAN: maybe wild-memory-access in range [0xdead000000000178-0xdead00000000017f] CPU: 0 UID: 1000 PID: 100 Comm: repro_userns RIP: 0010:__tcp_ao_do_lookup+0x107/0x1c0 Call Trace: <IRQ> __tcp_ao_do_lookup+0x107/0x1c0 tcp_ao_inbound_lookup.constprop.0+0x12a/0x200 tcp_inbound_ao_hash+0x5ea/0x1520 tcp_inbound_hash+0x7ce/0x1240 tcp_v4_rcv+0x1e7a/0x3e10 ... Restore the RCU grace period: re-add struct rcu_head to tcp_ao_info and replace the synchronous tcp_ao_info_free() with a call_rcu() callback. Readers that captured tp->ao_info before rcu_assign_pointer NULLed it now see the object remain valid until rcu_read_unlock(). With the patch applied the reproducer runs cleanly for 2000 iterations on the same kernel build. Fixes: 51e547e8c89c ("tcp: Free TCP-AO/TCP-MD5 info/keys without RCU") Cc: stable@vger.kernel.org # v6.18+ Reviewed-by: Dmitry Safonov <dima@arista.com> Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> Link: https://patch.msgid.link/20260625-tcp-md5-connect-v3-1-1fd313d6c1e0@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-29tipc: fix out-of-bounds read in broadcast Gap ACK blocksSamuel Page
A broadcast PROTOCOL/STATE_MSG can carry a Gap ACK blocks record in its data area. tipc_get_gap_ack_blks() only verifies that the record's len field is self-consistent with its ugack_cnt/bgack_cnt counts (sz == struct_size(p, gacks, ugack_cnt + bgack_cnt)); it does not check that the record actually fits in the message data area, msg_data_sz(). The unicast caller tipc_link_proto_rcv() bounds it ("if (glen > dlen) break;"), but the broadcast caller tipc_bcast_sync_rcv() discards the returned size, so tipc_link_advance_transmq() copies the record off the receive skb with an attacker-controlled count: this_ga = kmemdup(ga, struct_size(ga, gacks, ga->bgack_cnt), GFP_ATOMIC); A TIPC neighbour that negotiated TIPC_GAP_ACK_BLOCK triggers it with one ordinary broadcast STATE_MSG (msg_bc_ack_invalid() clear), sized so its data area is short, carrying a Gap ACK record with len = 0x400, bgack_cnt = 0xff and ugack_cnt = 0. len then equals struct_size(p, gacks, 255), so the consistency check passes and ga is non-NULL; kmemdup() reads struct_size(ga, gacks, 255) = 1024 bytes out of the much smaller skb: BUG: KASAN: slab-out-of-bounds in kmemdup_noprof+0x48/0x60 Read of size 1024 at addr ffff0000c7030d38 by task poc864/69 Call trace: kmemdup_noprof+0x48/0x60 tipc_link_advance_transmq+0x86c/0xb80 tipc_link_bc_ack_rcv+0x19c/0x1e0 tipc_bcast_sync_rcv+0x1c4/0x2c4 tipc_rcv+0x85c/0x1340 tipc_l2_rcv_msg+0xac/0x104 The buggy address belongs to the object at ffff0000c7030d00 which belongs to the cache skbuff_small_head of size 704 The buggy address is located 56 bytes inside of allocated 704-byte region [ffff0000c7030d00, ffff0000c7030fc0) The copied-out bytes are subsequently consumed as gap/ack values, but the read is already out of bounds at the kmemdup() regardless of how they are used. The unicast STATE path drops such a message: "if (glen > dlen) break;" skips the rest of STATE_MSG handling and the skb is freed. Make the broadcast path drop it too. tipc_bcast_sync_rcv() now bounds the record against msg_data_sz() and, when it does not fit, reports it back through tipc_node_bc_sync_rcv() to tipc_rcv() so the skb is discarded rather than processed. ga is not cleared on this path: ga == NULL already means "legacy peer without Selective ACK", a distinct legitimate state. Fixes: d7626b5acff9 ("tipc: introduce Gap ACK blocks for broadcast link") Cc: stable@vger.kernel.org Signed-off-by: Samuel Page <sam@bynar.io> Reviewed-by: Tung Nguyen <tung.quang.nguyen@est.tech> Link: https://patch.msgid.link/20260625143815.1525412-1-sam@bynar.io Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-29af_unix: use scoped_with_init_fs() for coredump socket lookupChristian Brauner
Use scoped_with_init_fs() to temporarily override current->fs for the coredump unix socket path resolution. This replaces the init_root() + vfs_path_lookup() pattern with scoped_with_init_fs() + kern_path(). The old code used LOOKUP_BENEATH to confine the lookup beneath init's root. This is dropped because the coredump socket path is absolute and resolved from root (where ".." is a no-op), and LOOKUP_NO_SYMLINKS already blocks any symlink-based escape. LOOKUP_BENEATH was redundant in this context. unix_find_bsd(SOCK_COREDUMP) ← coredump_sock_connect() ← do_coredump() — same crashing userspace process Same security rationale as coredump. Link: https://patch.msgid.link/20260601-work-kthread-nullfs-v4-18-77ee053060e0@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-06-29fs: Add bpf_sock_read_xattr() kfunc to read socket xattrsChristian Brauner
In c8db08110cbe ("Merge tag 'vfs-7.1-rc1.xattr' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs") we added support for extended attributes for sockets. This comes in two flavors: sockfs and non-sockfs/filesystem sockets. Filesystem sockets are actual filesystem objects so reading xattrs must use dedicated fs helpers such as bpf_get_dentry_xattr() and bpf_get_file_xattr(). Those are inherently sleeping operations. Sockfs sockets on the other hand don't need to use sleeping operations as the underlying data structure is lockless. In addition, retrieval of sockfs extended attributes often happens from LSM hooks that only provide struct socket and it's completely nonsensical to grab a reference to a file, then force a sleeping operation to retrieve the xattr and drop the reference. We know that the sockfs file cannot go away while the LSM hook runs. This series adds a bpf_sock_read_xattr() kfunc that, given a struct socket, reads a user.* extended attribute from the socket's sockfs inode into a bpf_dynptr. Together with fsetxattr() from userspace this lets a process label a socket with a user.* xattr and have a BPF LSM program retrieve that label locklessly. The kfunc mirrors the existing bpf_cgroup_read_xattr(), including the restriction to the user.* namespace. systemd uses user.* xattrs on sockets to implement socket rate limiting and to tag sockets for other purposes [1] such as implementing a varlink registry. There is currently no efficient way for a BPF program to read those labels back. The new helper allows a listening socket marked with an extended attribute to be read back during bind/connect and then act on the connect()ing socket. Extended attributes make it possible to allow an unprivileged user manager such as systemd --user to mark sockets from userspace and then rediscover them or implement policies. The kfunc is registered KF_RCU and only for BPF LSM programs. A struct socket is only guaranteed to live in sockfs when an LSM socket hook hands it out, which is what keeps SOCK_INODE() valid. Sockets that embed struct socket outside sockfs (tun, tap) are only reachable from tracing programs and are excluded by the registration. (Btw, for consistency it would be nice to force allocation of struct socket from sockfs instead of simply embedding it in e.g., struct tun_file which makes the SOCKFS_I() pattern a hazard - at least outside of sockfs functions.) The read never sleeps and takes no lock. For sockfs the value lives in the inode's in-memory xattr store and simple_xattr_get() resolves it with an RCU-protected rhashtable lookup, taking neither the inode lock nor any xattr lock. The kfunc is therefore usable from both sleepable and non-sleepable LSM hooks. Link: https://github.com/systemd/systemd/pull/40559 [1] Link: https://patch.msgid.link/20260617-work-bpf-sock-xattr-v1-1-a1276f7c9da3@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-06-28batman-adv: tp_meter: delay allocation of unacked entrySven Eckelmann
When batadv_tp_handle_out_of_order() searches the already existing list of unacked packets, it can often find an entry to merge with. In this case, it would be a waste of time and resources to allocate a batadv_tp_unacked which is then immediately freed again. Instead, search first through the list. Only when no mergeable entry could be found, it is necessary to record the place to allocate+store the new entry. Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: tp_meter: adjust name of receiver lockSven Eckelmann
The lock used to protect the receiver from reading/writing in parallel to ack sequence number relevant data was still called unacked_lock. But it is no longer only about the unacked_list. Use a broader term to reflect this. Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: tp_meter: keep unacked list for receiversSven Eckelmann
There is no need to share the unacked list between sender and receivers. Only receivers will ever write to and read from it. The initialization in batadv_tp_start() was therefore never needed. After its removal, it is enough to just store it in struct batadv_tp_receiver. Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: tp_meter: combine adjacent/overlapping unacked entriesSven Eckelmann
Right at the point when the receiver gets the first packet with a seqno gap (due to some packet loss/reordering), entries in the unacked list are created. They are (besides direct seqno matches) are not combined. A lot more then necessary entries are therefore created. Not for each gap but for each packet. This increases the memory consumption and management overhead. But it is trivial to handle overlapping or adjacent sequence number ranges during the insert. Only the handling of closed gaps by a new packets requires an extra step after the insert. Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: tp_meter: simplify unordered ack calculationSven Eckelmann
When batadv_tp_ack_unordered() goes through the list of unacked sequence numbers and checks for now closed gaps, it is first calculating a delta of the sequence numbers which could be acked. Just to revert this calculation in the next steps to the sequence number which would be ackable. Skip the delta step and directly work with the sequence numbers. Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: tvlv: extract tvlv header iteratorSven Eckelmann
batadv_tvlv_containers_contain() and batadv_tvlv_containers_process() are using the same code to iterate through the TVLV containers. To simplify the code, extract the shared portions of both functions. Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: iv: drop migration check for batadv_hard_ifaceSven Eckelmann
With the immutability guarantee of batadv_hard_iface->mesh_iface, the check for "changed" (or NULL) mesh_iface is no longer necessary because a batadv_hard_iface can no longer migrate from one batadv_mesh_iface to another one. Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28Revert "batman-adv: v: stop OGMv2 on disabled interface"Sven Eckelmann
With the immutability guarantee of batadv_hard_iface->mesh_iface, the check for "changed" (or NULL) mesh_iface doesn't work anymore and is also no longer necessary. The extra (complicated) code for the sending of OGMv2s can therefore be removed and the original code can be used again. This reverts commit f8ce8b8331a1bc44ad4905886a482214d428b253. Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: drop NULL check for immutable hardif->mesh_ifaceSven Eckelmann
The batadv_hard_iface->mesh_iface became immutable after the global batadv_hardif_list was removed and batadv_hard_iface only exists when it is assigned to an mesh_iface. This member can never become NULL and thus a check is now unnecessary. Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: drop unneeded goto and initialization from ↵Nora Schiffer
batadv_hardif_disable_interface() The only use of the label was too early for primary_if to be set anyways. Also move the put of primary_if further up to hold the reference only as long as necessary, hopefully avoiding the need to re-introduce the goto label with future code changes. Signed-off-by: Nora Schiffer <neocturne@universe-factory.net> Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: move hardif generation counter into batadv_privNora Schiffer
The counter doesn't need to be global. Signed-off-by: Nora Schiffer <neocturne@universe-factory.net> Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: remove BATADV_IF_NOT_IN_USE hardif stateNora Schiffer
With hardifs only existing while an interface is part of a mesh, the BATADV_IF_NOT_IN_USE state has become redundant. Signed-off-by: Nora Schiffer <neocturne@universe-factory.net> Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: make hard_iface->mesh_iface immutableSven Eckelmann
With the hard_iface now being created for a specific mesh_iface, it is beneficial not to set mesh_iface to NULL when the interface is disabled, but instead keeping it immutable after the initial setup of the hard_iface. By also holding the reference to the mesh_iface until the hard_iface is released, hard_ifaces iterated over under RCU will always point to a valid mesh_iface. Co-developed-by: Nora Schiffer <neocturne@universe-factory.net> Signed-off-by: Nora Schiffer <neocturne@universe-factory.net> Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: remove global hardif listNora Schiffer
With interfaces being kept track of as iflink private data, there is no need for the global list anymore. batadv_hardif_get_by_netdev() can now use netdev_master_upper_dev_get()+netdev_lower_dev_get_private() to find the hardif corresponding to a netdev. Signed-off-by: Nora Schiffer <neocturne@universe-factory.net> Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: create hardif only for netdevs that are part of a meshNora Schiffer
batman-adv is using netdev notifiers to create a hard_iface struct for every Ethernet-like netdev in the system. These hardifs are tracked in a global linked list, which results in a few performance issues: Lookups in this list are O(n) in the total number of netdevs. As a hardif is looked up when a netdev is removed, this also takes O(n) in the number of netdevs, and removing n netdevs may take O(n^2). This slowdown will always happen when the batman-adv module is loaded, no mesh needs to be active. With the hardif being referenced as iflink private data, the global list is only needed for hardifs that are *not* part of a mesh (that is, the hardif is unused). To prepare for removing the global list, only create a hardif struct when an interface is added to a mesh and destroy it on removal. As adding/removing and enabling/disabling a hardif become one and the same, batadv_hardif_add_interface() is merged into batadv_hardif_enable_interface(), and batadv_hardif_remove_interface() can be dropped altogether. Signed-off-by: Nora Schiffer <neocturne@universe-factory.net> Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: dat: ensure accessible eth_hdr proto fieldSven Eckelmann
When batadv_get_vid() accesses the proto field of the ethernet header, it is not checking if the data itself is accessible. The caller is responsible for it. But in contrast to other call sites, batadv_dat_get_vid() and its caller didn't make sure this is true. This could have caused an out-of-bounds access. Cc: stable@vger.kernel.org Reported-by: Sashiko <sashiko-bot@kernel.org> Fixes: be1db4f6615b ("batman-adv: make the Distributed ARP Table vlan aware") Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: bla: reacquire gw address after skb reallocSven Eckelmann
The pskb_may_pull() called by batadv_bla_is_backbone_gw() could reallocate the buffer behind the skb. Variables which were pointing to the old buffer need to be reassigned to avoid an use-after-free. Cc: stable@vger.kernel.org Fixes: 9e794b6bf4a2 ("batman-adv: drop unicast packets from other backbone gw") Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: dat: acquire ARP hw source only after skb reallocSven Eckelmann
The pskb_may_pull() called by batadv_get_vid() could reallocate the buffer behind the skb. Variables which were pointing to the old buffer need to be reassigned to avoid an use-after-free. Cc: stable@vger.kernel.org Fixes: b61ec31c8575 ("batman-adv: Snoop DHCPACKs for DAT") Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: gw: acquire ethernet header only after skb reallocSven Eckelmann
The pskb_may_pull() called by batadv_get_vid() could reallocate the buffer behind the skb. Variables which were pointing to the old buffer need to be reassigned to avoid an use-after-free. Cc: stable@vger.kernel.org Fixes: 6c413b1c22a2 ("batman-adv: send every DHCP packet as bat-unicast") Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: access unicast_ttvn skb->data only after skb reallocSven Eckelmann
The pskb_may_pull() called by batadv_get_vid() could reallocate the buffer behind the skb. Variables which were pointing to the old buffer need to be reassigned to avoid an use-after-free. This was done correctly for the ethernet header but missed for the unicast_packet pointer. Cc: stable@vger.kernel.org Reported-by: Sashiko <sashiko-bot@kernel.org> Fixes: c018ad3de61a ("batman-adv: add the VLAN ID attribute to the TT entry") Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-28batman-adv: retrieve ethhdr after potential skb realloc on RXSven Eckelmann
pskb_may_pull() in batadv_interface_rx() could reallocate the buffer behind the skb. Variables which were pointing to the old buffer need to be reassigned to avoid an use-after-free. This was done correctly for the VLAN header but missed for the ethernet header which is later used for the TT and AP isolation handling. Cc: stable@vger.kernel.org Reported-by: Sashiko <sashiko-bot@kernel.org> Fixes: c6c8fea29769 ("net: Add batman-adv meshing protocol") Fixes: c78296665c3d ("batman-adv: Check skb size before using encapsulated ETH+VLAN header") Signed-off-by: Sven Eckelmann <sven@narfation.org>
2026-06-27net: dsa: Fix skb ownership in taggersLinus Walleij
The tag_8021q.c tagger calls vlan_insert_tag() in dsa_8021q_xmit(). vlan_insert_tag() will consume the skb with kfree_skb() on failure and return NULL. When NULL is returned as error code to ->xmit() in dsa_user_xmit() it will free the same skb again leading to a double-free. The idea of dsa_user_xmit() and dsa_switch_rcv() dropping the skb they held before the call to ->xmit() and ->rcv() is conceptually wrong: the pattern elsewhere in the networking code is that consumers drop their skb:s on failure. Modify the ->xmit() and ->rcv() call sites to not drop the SKB if the taggers return NULL from any of these calls. Move those drops into the taggers so every callback error path that retains ownership consumes the skb before returning NULL. Keep the existing helper ownership rules: VLAN insertion helpers already free on failure (this is the case in tag_8021q.c), while deferred transmit paths either transfer the skb reference to worker context or hold a worker reference with skb_get() and drop the caller's reference. For SJA1105 meta RX, transfer the buffered stampable skb under the meta lock and return NULL while the skb is waiting for its meta frame: the skb is not dropped in this case. NOTICE: Backporting patches to taggers (e.g. for stable kernels) after this point cannot be mechanical or they will introduce double kfree_skb(). Reported-by: Sashiko AI Review <sashiko-bot@kernel.org> Closes: https://lore.kernel.org/r/20260610153952.1685895-1-kuba@kernel.org/ Suggested-by: Jakub Kicinski <kuba@kernel.org> Acked-by: David Yang <mmyangfl@gmail.com> # yt921x Acked-by: Kurt Kanzenbach <kurt@linutronix.de> # hellcreek Reviewed-by: Wei Fang <wei.fang@nxp.com> # netc Signed-off-by: Linus Walleij <linusw@kernel.org> Link: https://patch.msgid.link/20260625-dsa-fix-free-skb-v5-1-b5931e4cbdb0@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-27sctp: add INIT verification after cookie unpackingXin Long
In SCTP handshake, the INIT chunk is initially processed by the server and embedded into the cookie carried in INIT-ACK. The client then returns this cookie via COOKIE-ECHO, where the server unpacks it and reconstructs the original INIT chunk. When cookie authentication is enabled, the cookie contents are protected against tampering, so reusing the unpacked INIT without re-verification is safe. However, when cookie authentication is disabled, the reconstructed INIT can no longer be trusted. In this case, the INIT must be explicitly validated after unpacking to avoid processing potentially tampered data. Add sctp_verify_init() checks after cookie unpacking in COOKIE-ECHO processing paths (sctp_sf_do_5_1D_ce() and sctp_sf_do_5_2_4_dupcook()) when cookie_auth_enable is disabled. On failure, the new association is freed and the packet is discarded. Also tighten cookie validation in sctp_unpack_cookie() by verifying the embedded chunk type is SCTP_CID_INIT before treating it as an INIT chunk. Finally, update sctp_verify_init() to validate parameter bounds using the actual embedded INIT length instead of chunk->chunk_end, since the INIT stored in COOKIE-ECHO may not span the entire chunk buffer. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Xin Long <lucien.xin@gmail.com> Link: https://patch.msgid.link/ebcbbac574815b0850f371b4bdb02f2e602b94d3.1782341592.git.lucien.xin@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-27netpoll: fix a use-after-free on shutdown pathBreno Leitao
There is a use-after-free error on netpoll, which is clearly detected by KASAN. BUG: KASAN: slab-use-after-free in _raw_spin_lock_irqsave+0x3b/0x80 Read of size 1 at addr ... by task kworker/9:1 Workqueue: events queue_process Call Trace: skb_dequeue+0x1e/0xb0 queue_process+0x2c/0x600 process_scheduled_works+0x4b6/0x850 worker_thread+0x414/0x5a0 Allocated by task 242: __netpoll_setup+0x201/0x4a0 netpoll_setup+0x249/0x550 enabled_store+0x32f/0x380 Freed by task 0: kfree+0x1b7/0x540 rcu_core+0x3f8/0x7a0 The problem happens when there is a pending TX worker running in parallel with the cleanup path. This is what happens on netpoll shutdown path: 1) __netpoll_cleanup() is called 2) set dev->npinfo to NULL 3) call_rcu() with rcu_cleanup_netpoll_info() 3.1) rcu_cleanup_netpoll_info() tries to cancel all workers with cancel_delayed_work(), but doesn't wait for the worker to finish 4) and kfree(npinfo); Because 3.1) doesn't really cancel the work, as the comment says "we can't call cancel_delayed_work_sync here, as we are in softirq", the TX worker can run after 4). Tl;DR: queue_process() is not an RCU reader, it reaches npinfo through the work item via container_of(). Use disable_delayed_work_sync() to ensure the worker is completely stopped and prevent any future re-arming attempts. Once npinfo is set to NULL, senders will bail out and not queue new work. The disable flag ensures any in-flight re-arming attempts also fail silently. In the future, we can do the cleanup inline here without needing the npinfo->rcu rcu_head, but that is net-next material. Cc: stable@vger.kernel.org Fixes: 38e6bc185d95 ("netpoll: make __netpoll_cleanup non-block") Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com> Signed-off-by: Breno Leitao <leitao@debian.org> Link: https://patch.msgid.link/20260625-netpoll_rcu_fix-v2-1-0748ffac1e98@debian.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-27sctp: fix SCTP_RESET_STREAMS stream list length limitYousef Alhouseen
SCTP_RESET_STREAMS carries a flexible array of u16 stream IDs, but the optlen clamps treat USHRT_MAX as a byte count and then multiply sizeof(__u16) by the fixed header size. That caps the copied and validated option buffer at about 64 KiB, which rejects valid requests containing more than about half of the u16 stream ID range. Use struct_size_t() for the maximum struct sctp_reset_streams layout instead, so the bound matches the flexible array described by srs_number_streams. Fixes: 5960cefab9df ("sctp: add a ceiling to optlen in some sockopts") Acked-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com> Link: https://patch.msgid.link/20260625142354.2600-1-alhouseenyousef@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-26net/sched: sch_multiq: Replace direct dequeue call with peek and ↵Bryam Vargas
qdisc_dequeue_peeked multiq_dequeue() takes a packet from a band's child with a direct ->dequeue() call after multiq_peek() peeked it. When the child is non-work-conserving the peek stashes the skb in the child's gso_skb, so the direct dequeue returns a different skb and orphans the stash, desyncing the child's qlen/backlog. With a qfq child reached through a peeking parent (e.g. tbf) this re-enters the child on an emptied list and dereferences NULL, panicking the kernel from softirq on ordinary egress. Take the packet through qdisc_dequeue_peeked(), as sch_prio already does and as sch_red and sch_sfb were just fixed to do. The helper is a no-op when the child has no stash, so a work-conserving child is unaffected. Fixes: 77be155cba4e ("pkt_sched: Add peek emulation for non-work-conserving qdiscs.") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Reviewed-by: Victor Nogueira <victor@mojatatu.com> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Link: https://patch.msgid.link/20260625-b4-disp-31bcb279-v1-2-85c40b83c529@proton.me Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-26net/sched: sch_taprio: Replace direct dequeue call with peek and ↵Bryam Vargas
qdisc_dequeue_peeked When taprio's software path peeks a non-work-conserving child qdisc, the child stashes the peeked skb in its gso_skb; taprio_dequeue_from_txq() then takes the packet with a direct child ->dequeue() call, which ignores that stash, orphans the peeked skb and desyncs the child's qlen/backlog. With a qfq child this re-enters the child on an emptied list and dereferences NULL, panicking the kernel from softirq on ordinary egress. Take the packet through qdisc_dequeue_peeked(), as sch_red and sch_sfb now do. The helper returns the child's stashed skb first and is a no-op when there is none, so a work-conserving child is unaffected and the gated path now consumes the skb whose length was charged to the budget. Fixes: 5a781ccbd19e ("tc: Add support for configuring the taprio scheduler") Cc: stable@vger.kernel.org Cc: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Reviewed-by: Victor Nogueira <victor@mojatatu.com> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Link: https://patch.msgid.link/20260625-b4-disp-31bcb279-v1-1-85c40b83c529@proton.me Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-26seg6: validate SRH length before reading fixed fieldsNuoqi Gui
seg6_validate_srh() reads fixed SRH fields such as srh->type and srh->hdrlen before checking that the supplied length covers the fixed struct ipv6_sr_hdr fields. The BPF SEG6 encap path reaches this with a BPF program-supplied pointer and length: bpf_lwt_push_encap() and the SEG6 local BPF END_B6 and END_B6_ENCAP actions call bpf_push_seg6_encap(), which forwards the length to seg6_validate_srh() with no minimum-size guard. A 2-byte SEG6 encap header can therefore make the validator read srh->type at offset 2 beyond the caller-supplied buffer. Reject lengths shorter than the fixed SRH at the top of seg6_validate_srh(), before any field is read. This fixes the BPF helper path and keeps the common validator robust. Fixes: fe94cc290f53 ("bpf: Add IPv6 Segment Routing helpers") Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn> Reviewed-by: Andrea Mayer <andrea.mayer@uniroma2.it> Link: https://patch.msgid.link/20260623-f01-17-seg6-srh-len-v2-1-2edc40e9e3e1@mails.tsinghua.edu.cn Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-26xfrm: fix stale skb->prev after async crypto steals a GSO segmentPetr Wozniak
skb_gso_segment() leaves the segment list head with ->prev pointing at the last segment, an invariant validate_xmit_skb_list() relies on when it sets its tail pointer (tail = skb->prev). When validate_xmit_xfrm() walks a GSO list and some segments are stolen by async crypto (->xmit() returns -EINPROGRESS), those segments are unlinked from the list but the head ->prev is never updated. If the last segment is the one stolen, the returned head still has ->prev pointing at it, even though it is now owned by the crypto engine and may be freed. validate_xmit_skb_list() later does tail->next = skb, writing through that stale pointer -- a use-after-free. Repoint skb->prev at the last retained segment before returning. Fixes: f53c723902d1 ("net: Add asynchronous callbacks for xfrm on layer 2.") Signed-off-by: Petr Wozniak <petr.wozniak@gmail.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-06-26xfrm: propagate -EINPROGRESS from validate_xmit_xfrm()Petr Wozniak
validate_xmit_xfrm() returns NULL both when a packet is dropped and when it is stolen by async crypto (-EINPROGRESS from ->xmit()). Callers cannot distinguish the two cases. f53c723902d1 ("net: Add asynchronous callbacks for xfrm on layer 2.") changed the semantics of a NULL return from "dropped" to "stolen or dropped", but __dev_queue_xmit() was not updated. On virtual/bridge interfaces (noqueue qdisc) __dev_queue_xmit() initialises rc=-ENOMEM and jumps to out: when skb is NULL, returning -ENOMEM to the caller even though the packet will be delivered correctly via xfrm_dev_resume(). Return ERR_PTR(-EINPROGRESS) from validate_xmit_xfrm() for the async case so callers can tell it apart from a real drop. Update __dev_queue_xmit() to handle ERR_PTR(-EINPROGRESS) from validate_xmit_skb() correctly. Update validate_xmit_skb_list() to use IS_ERR_OR_NULL() so that ERR_PTR(-EINPROGRESS) is not mistakenly added to the transmitted list. Fixes: f53c723902d1 ("net: Add asynchronous callbacks for xfrm on layer 2.") Suggested-by: Sabrina Dubroca <sd@queasysnail.net> Signed-off-by: Petr Wozniak <petr.wozniak@gmail.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2026-06-25bpf, sockmap: reject a packet-modifying SK_SKB stream parserSechang Lim
sk_psock_strp_parse() runs the BPF_PROG_TYPE_SK_SKB stream-parser program to find the length of the next message. strparser assembles a message out of several received skbs by chaining them onto the head's frag_list and recording where to append the next one in strp->skb_nextp: *strp->skb_nextp = skb; strp->skb_nextp = &skb->next; and then calls the parser on the head: len = (*strp->cb.parse_msg)(strp, head); The parser is only meant to inspect the skb, but the program may call bpf_skb_change_tail() -- or the sibling bpf_skb_pull_data(), bpf_skb_change_head(), bpf_skb_adjust_room(), all allowed for SK_SKB. Once the head carries a frag_list these go ... -> skb_ensure_writable -> pskb_may_pull -> __pskb_pull_tail and __pskb_pull_tail() frees the frag_list skbs that strparser still tracks through skb_nextp: while ((list = skb_shinfo(skb)->frag_list) != insp) { skb_shinfo(skb)->frag_list = list->next; consume_skb(list); } strp->skb_nextp now points into a freed sk_buff. The next segment of the same message arrives in __strp_recv(), which links it with *strp->skb_nextp = skb, an 8-byte write into the freed skb. The free and the write happen in different __strp_recv() calls, so the message has to span at least three segments before it triggers. BUG: KASAN: slab-use-after-free in __strp_recv+0x447/0xda0 Write of size 8 at addr ffff88810db86140 by task repro/349 Call Trace: <IRQ> __strp_recv+0x447/0xda0 __tcp_read_sock+0x13d/0x590 tcp_bpf_strp_read_sock+0x195/0x320 strp_data_ready+0x267/0x340 sk_psock_strp_data_ready+0x1ce/0x350 tcp_data_queue+0x1364/0x2fd0 tcp_rcv_established+0xe07/0x1640 [...] Allocated by task 349: skb_clone+0x17b/0x210 __strp_recv+0x2c3/0xda0 __tcp_read_sock+0x13d/0x590 [...] Freed by task 349: kmem_cache_free+0x150/0x570 __pskb_pull_tail+0x57b/0xc20 skb_ensure_writable+0x236/0x260 __bpf_skb_change_tail+0x1d4/0x590 sk_skb_change_tail+0x2a/0x40 bpf_prog_1b285dcd6c41373e+0x27/0x30 bpf_prog_run_pin_on_cpu+0xf3/0x260 sk_psock_strp_parse+0x118/0x1e0 __strp_recv+0x4f6/0xda0 [...] The same resize also leaves the head's length inconsistent with its frags, so a later __pskb_pull_tail() can instead hit the BUG_ON(skb_copy_bits(...)) in net/core/skbuff.c. A stream parser is only meant to measure the next message, not to modify the packet. Reject a parser whose program can change packet data (prog->aux->changes_pkt_data) at attach time. The check is shared by sock_map_prog_update() and sock_map_link_update_prog(), which between them cover prog attach, link create and link update. Verdict programs are unaffected and may still modify the skb. Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev> Signed-off-by: Sechang Lim <rhkrqnwk98@gmail.com> Link: https://lore.kernel.org/r/20260620024423.4141004-3-rhkrqnwk98@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-06-25bpf: Support BPF_F_EGRESS with bpf_redirect_peerJordan Rife
We have several use cases where a pod injects traffic into the datapath of another so that the traffic appears to have originated from that pod. One such use case is a synthetic flow generator which injects synthetic traffic into a pod's datapath to enable dynamic probing and debugging. Another is a transparent proxy where connections originating from one pod are redirected towards another which proxies that connection. The new connection is bound to the IP of the original pod using IP_TRANSPARENT and its traffic is injected into that pod's datapath and handled as if it had originated there. This can be used for mTLS, etc. We use bpf_redirect(BPF_F_INGRESS) to direct traffic leaving the proxy, flow generator, etc. towards the target pod, ensuring that eBPF programs that are meant to intercept traffic leaving that pod are executed. However, this doesn't work with netkit. With netkit, an ingress redirection from proxy to workload skips eBPF programs that are meant to intercept traffic leaving the pod, since they reside on the netkit peer device. One workaround is to attach the same program to both the netkit peer device and the TCX ingress hook for the netkit pair's primary interface, but a) This seems hacky and we need to be careful not to run the same program twice for the same skb in cases where we want to pass that traffic to the host stack. b) We're trying to keep the proxy redirection / traffic injection systems as modular and separated from Cilium as possible, the system that manages netkit setup and core eBPF programming. It would be handy if instead we could redirect traffic directly from one netkit peer device to another. This patch proposes an extension to bpf_redirect_peer to allow us to do just that. With this patch, the BPF_F_EGRESS flag tells bpf_redirect_peer to emit the skb in the egress direction of the target interface's peer device While the main use case is netkit, I suppose you could also use this mode with veth as well if, e.g., there were some eBPF programs attached to that side of the veth pair that needed to intercept traffic. +---------------------------------------------------------------------+ | +-------------------------+ 6. bpf_redirect_neigh(eth0) | | | pod (10.244.0.10) | ------------------------ | | | | | | | | | +--------+ | | +---------+ | | | | 1. packet -->| | | | | | | | | | leaves ^ | netkit |<===========|======| netkit | | | | | | | peer |=======(eBPF)=====>| primary | | | | | | | | | | | | | | | | | +--------+ | | +---------+ | | | | | | | 2. bpf_redirect v | | +-----------|-------------+ |___________________ +-------| | | | | eth0 | | | 5. bpf_redirect_peer(BPF_F_EGRESS) | +-------| | |________________________ | | | +-------------------------+ | | | | | proxy (10.244.0.11) | | | | | | IP_TRANSPARENT | | | | | | +--------+ | | +---------+ | | | | 3. packet <--| | | | | |<-- | | | enters | netkit |<===========|======| netkit | | | | [proxy] | peer |=======(eBPF)=====>| primary | | | | 4. packet -->| | | | | | | | leaves +--------+ | +---------+ | | | sip=10.244.0.10 | | | +-------------------------+ | +---------------------------------------------------------------------+ Using the proxy use case as an example, in step 5 we would redirect traffic leaving the proxy towards the pod's peer device using bpf_redirect_peer(BPF_F_EGRESS). As a bonus, since the skb doesn't have to go through the backlog queue it can take full advantage of netkit's performance benefits. I set up a test where outgoing iperf3 traffic is injected into the datapath of another pod using either bpf_redirect_peer(BPF_F_EGRESS) or bpf_redirect(BPF_F_INGRESS). I used Cilium's eBPF host routing mode which skips the host stack and uses BPF redirect helpers to do all the routing. (net.ipv4.tcp_congestion_control=cubic,mtu=1500,100GiB link,Cilium eBPF host routing mode) BASELINE [bpf_redirect(BPF_F_INGRESS)] 1. [iperf pod] ==bpf_redirect([pod b], BPF_F_INGRESS)==> [pod b] 2. [pod b] ==bpf_redirect_neigh([eth0])==> eth0 3. eth0 ==over network==> [host b] [ ID] Interval Transfer Bitrate Retr [ 5] 0.00-60.00 sec 231 GBytes 33.0 Gbits/sec 12060 sender [ 5] 0.00-60.00 sec 230 GBytes 33.0 Gbits/sec receiver TEST [bpf_redirect_peer(BPF_F_EGRESS)] 1. [iperf pod] ==bpf_redirect_peer([pod b], BPF_F_EGRESS)==> [pod b] 2. [pod b] ==bpf_redirect_neigh([eth0])==> eth0 3. eth0 ==over network==> [host b] [ ID] Interval Transfer Bitrate Retr [ 5] 0.00-60.00 sec 272 GBytes 38.9 Gbits/sec 0 sender [ 5] 0.00-60.00 sec 272 GBytes 38.9 Gbits/sec receiver In this test, using bpf_redirect_peer(BPF_F_EGRESS) for the hop from [iperf pod] to [pod b] led to ~18% more throughput compared to bpf_redirect(BPF_F_INGRESS). Signed-off-by: Jordan Rife <jordan@jrife.io> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Paul Chaignon <paul.chaignon@gmail.com> Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev> Link: https://lore.kernel.org/r/20260618182035.43811-2-jordan@jrife.io Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-06-25Merge tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpfLinus Torvalds
Pull bpf fixes from Alexei Starovoitov: - Fix effective prog array index with BPF_F_PREORDER (Amery Hung) - Zero-initialize the fib lookup flow struct (Avinash Duduskar) - Disable xfrm_decode_session hook attachment (Bradley Morgan) - Allow type tag BTF records to succeed other modifier records (Emil Tsalapatis) - Fix build_id caching in stack_map_get_build_id_offset() (Ihor Solodrai) - Add missing access_ok call to copy_user_syms (Jiri Olsa) - Fix stack slot index in nospec checks (Nuoqi Gui) - Preserve pointer spill metadata during half-slot cleanup (Nuoqi Gui) - Fix partial copy of non-linear test_run output (Sun Jian) - Fix BPF_PROG_ASSOC_STRUCT_OPS last field check (Thiébaud Weksteen) - Reset register bounds before narrowing retval range (Tristan Madani) - Fix vmlinux BTF leak in bpftool cgroup commands (Yichong Chen) - Guard error writes in conntrack kfuncs (Yiyang Chen) * tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: bpf: Disable xfrm_decode_session hook attachment selftests/bpf: Add test for stale bounds on LSM retval context load bpf: Reset register bounds before narrowing retval range in check_mem_access() selftests/bpf: Cover small conntrack opts error writes bpf: Guard conntrack opts error writes selftests/bpf: Cover half-slot cleanup of pointer spills bpf: Preserve pointer spill metadata during half-slot cleanup selftests/bpf: Test cgroup link replace with BPF_F_PREORDER bpf: Fix effective prog array index with BPF_F_PREORDER bpf: Fix BPF_PROG_ASSOC_STRUCT_OPS last field check bpf: zero-initialize the fib lookup flow struct bpftool: Fix vmlinux BTF leak in cgroup commands bpf: Add missing access_ok call to copy_user_syms bpf: Allow type tag BTF records to succeed other modifier records bpf: Emit verbose message when prog-specific btf_struct_access rejects a write bpf: Fix build_id caching in stack_map_get_build_id_offset() bpf: Fix partial copy of non-linear test_run output selftests/bpf: Cover stack nospec slot indexing bpf: Fix stack slot index in nospec checks
2026-06-25Merge tag 'net-7.2-rc1' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net Pull networking fixes from Jakub Kicinski: "Including fixes from netfilter and IPsec. Current release - regressions: - do not acquire dev->tx_global_lock in netdev_watchdog_up() - ethtool: keep rtnl_lock for ops using ethtool_op_get_link() - fix deadlock in nested UP notifier events Current release - new code bugs: - eth: - cn20k: fix subbank free list indexing for search order - airoha: fix BQL underflow in shared QDMA TX ring Previous releases - regressions: - netfilter: - flowtable: fix offloaded ct timeout never being extended - nf_conncount: prevent connlimit drops for early confirmed ct Previous releases - always broken: - require CAP_NET_ADMIN in the originating netns when modifying cross-netns devices - report NAPI thread PID in the caller's pid namespace - mac802154: fix dirty frag in in-place crypto for IOT radios - sctp: hold socket lock when dumping endpoints in sctp_diag, avoid an overflow - eth: gve: fix header buffer corruption with header-split and HW-GRO - af_key: initialize alg_key_len for IPComp states, prevent OOB read" * tag 'net-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (213 commits) selftests: bonding: add a test for VLAN propagation over a bonded real device vlan: defer real device state propagation to netdev_work net: add the driver-facing netdev_work scheduling API net: turn the rx_mode work into a generic netdev_work facility net: ethtool: keep rtnl_lock for ops using ethtool_op_get_link() rxrpc: Fix rxrpc_rotate_tx_rotate() to check there's something to rotate rxrpc: Fix leak of released call in recvmsg(MSG_PEEK) rxrpc: Fix socket notification race rxrpc: Fix potential infinite loop in rxrpc_recvmsg() rxrpc: Fix oob challenge leak in cleanup after notification failure rxrpc: Fix the reception of a reply packet before data transmission afs: Fix uncancelled rxrpc OOB message handler afs: Fix further netns teardown to cancel the preallocation charger rxrpc: Fix double unlock in rxrpc_recvmsg() rxrpc: Fix leak of connection from OOB challenge rxrpc: Fix ACKALL packet handling net: hns3: differentiate autoneg default values between copper and fiber net: hns3: fix permanent link down deadlock after reset net: hns3: refactor MAC autoneg and speed configuration net: hns3: unify copper port ksettings configuration path ...
2026-06-25vlan: defer real device state propagation to netdev_workJakub Kicinski
vlan_device_event() generates nested UP/DOWN, MTU and feature change events. It executes an event for the VLAN device directly from the notifier - while the locks of the lower device are held. This causes deadlocks, for example: bond (3) bond_update_speed_duplex(vlan) | ^ v vlan (2) UP(vlan) (4) vlan_ethtool_get_link_ksettings() | ^ v dummy (1) UP(dummy) (5) __ethtool_get_link_ksettings() The dummy device is ops locked, vlan creates a nested event (2), then bond wants to ask vlan for link state (3). bond uses the "I'm already holding the instance lock" flavor of API. But in this case the lock held refers to vlan itself. We hit vlan's link settings trampoline (4) and call __ethtool_get_link_ksettings() which tries to lock dummy. Deadlock. There's no clean way for us to tell the vlan_ethtool_get_link_ksettings() that the caller is already in lower device's critical section. Defer the propagation to the per-netdev work facility instead: the notifier only schedules netdev_work_sched(vlandev, VLAN_WORK_*), and ndo_work (vlan_dev_work) applies the change later. Hopefully nobody expects the VLAN state changes to be instantaneous. If someone does expect the changes to be instantaneous we will have to do the same thing Stan did for rx_mode and "strategically" place sync calls, to make sure such delayed works are executed after we drop the ops lock but before we drop rtnl_lock. Stan suggests that if we need that down the line we may consider reshaping the mechanism into "async notifications". AFAICT only vlan does this sort of netdev open chaining, so as a first try I think that sticking the complexity into the vlan code makes sense. One corner case is that we need to cancel the event if user explicitly changes the state before work could run. Consider the following operations with vlan0 on top of dummy0: ip link set dev dummy0 up # queues work to up vlan0 ip link set dev vlan0 down # user explicitly downs the vlan ndo_work # acts on the stale event Reported-by: syzbot+09da62a8b78959ceb8bb@syzkaller.appspotmail.com Reported-by: syzbot+cb67c392b0b8f0fd0fc1@syzkaller.appspotmail.com Reported-by: syzbot+9bb8bd77f3966641f298@syzkaller.appspotmail.com Fixes: 9f275c2e9020 ("net: ethtool: make sure __ethtool_get_link_ksettings() is ops-locked") Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de> Acked-by: Stanislav Fomichev <sdf@fomichev.me> Link: https://patch.msgid.link/20260624182018.2445732-4-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-25net: add the driver-facing netdev_work scheduling APIJakub Kicinski
With an extra event mask we can easily extend the netdev work to also service driver-defined events. For advanced drivers this is probably not a perfect match, but it makes running deferred work easier in simple cases. Expose the netdev_work facility to drivers. Add helpers to schedule work and a dedicated ndo to perform the driver- -scheduled actions. Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Acked-by: Stanislav Fomichev <sdf@fomichev.me> Link: https://patch.msgid.link/20260624182018.2445732-3-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-25net: turn the rx_mode work into a generic netdev_work facilityJakub Kicinski
The rx_mode update runs from a workqueue: drivers have their ndo_set_rx_mode_async() callback executed by a single global work item under RTNL and ops lock. This is a useful pattern. Support multiple "events" that need to be serviced and make RX_MODE sync the first one. Call the events "core" because later on we will let drivers define and schedule their own. Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Acked-by: Stanislav Fomichev <sdf@fomichev.me> Link: https://patch.msgid.link/20260624182018.2445732-2-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>