summaryrefslogtreecommitdiff
path: root/net/sched
AgeCommit message (Collapse)Author
2 daysnet/sched: cake: reject overhead values that underflow lengthSamuel Moelius
CAKE accepts signed overhead values and stores them in an s16, but the adjusted packet length calculation uses unsigned arithmetic. A negative effective length can therefore wrap to a large value. Such configurations make rate accounting depend on integer wraparound rather than on the packet size userspace intended to model. A static netlink lower bound is not enough because packets reaching CAKE can be smaller than any reasonable manual-overhead allowance. Fold the signed overhead adjustment into the existing datapath MPU clamp so negative adjusted lengths are clamped before link-layer framing adjustments. Fixes: a729b7f0bd5b ("sch_cake: Add overhead compensation support to the rate shaper") Assisted-by: Codex:gpt-5.5-cyber-preview Signed-off-by: Samuel Moelius <sam.moelius@trailofbits.com> Acked-by: Toke Høiland-Jørgensen <toke@toke.dk> Link: https://patch.msgid.link/20260702000758.297407.e5c888d9d99d.cake-overhead-underflow@trailofbits.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
4 daysnet/sched: act_pedit: fix TOCTOU heap OOB write in tc offloadJamal Hadi Salim
There is a TOCTOU race condition in flower lockless approach between sizing a flow_rule buffer and filling it. zdi-disclosures@trendmicro.com reports: The cls_flower classifier operates with TCF_PROTO_OPS_DOIT_UNLOCKED (fl_change runs without RTNL), while RTM_NEWACTION holds RTNL, so the independent locking domains make the race reachable in practice. KASAN confirms: BUG: KASAN: slab-out-of-bounds in tcf_pedit_offload_act_setup+0x81b/0x930 Write of size 4 at addr ffff888001f27520 by task poc-toctou/312 The buggy address is located 0 bytes to the right of allocated 288-byte region [ffff888001f27400, ffff888001f27520) (cache kmalloc-512) Note: The result is a heap OOB write attacker-controlled content into the adjacent slab object (requires CAP_NET_ADMIN). The fix introduces reading tcfp_nkeys under act->tcfa_lock in all places using a new tcf_pedit_nkeys_locked() which replaces the old tcf_pedit_nkeys(). Additionally we close the remaining TOCTOU window between the sizing read and the fill reads by more careful accounting. Rather than silently truncating the key count, which leads to incorrect action semantics offloaded to hardware and secondary OOB writes if the remaining capacity is zero or consumed by prior actions, we enforce remaining capacity checks and return -ENOSPC if the required space exceeds the remaining capacity. Fixes: 71d0ed7079df ("net/act_pedit: Support using offset relative to the conventional network headers") Reported-by: zdi-disclosures@trendmicro.com Tested-by: Victor Nogueira <victor@mojatatu.com> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Link: https://patch.msgid.link/20260701161912.125355-1-jhs@mojatatu.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
7 daysnet/sched: sch_teql: move rcu_read_lock()/spin_lock() from _bh variantsJamal Hadi Salim
This is a followup based on sashiko comments [1] on commit e5b811fe7931 ("net/sched: sch_teql: Introduce slaves_lock to avoid race condition and UAF") Use plain rcu_read_lock()/spin_lock() in teql_master_xmit() instead of the _bh variants, since ndo_start_xmit is already invoked with BH disabled by the core stack and the _bh primitives can warn in_hardirq() when xmit is reached through netpoll or a softirq xmit path with hard IRQs disabled. Moves rcu_read_lock() after restart: label + adds rcu_read_unlock() before goto restart (fixes the unbounded RCU hold across retries) [1] https://sashiko.dev/#/patchset/20260628111229.669751-1-jhs%40mojatatu.com Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Fixes: e5b811fe7931 ("net/sched: sch_teql: Introduce slaves_lock to avoid race condition and UAF") Link: https://patch.msgid.link/20260630150922.238714-1-jhs@mojatatu.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
9 daysnet/sched: hhf: clear heavy-hitter state on resetSamuel Moelius
HHF reset does not clear the classifier state used to identify heavy hitters. Packets after reset can therefore be scheduled using flow history from before the reset. The reset operation should return the qdisc to an empty state. Clear the heavy-hitter classifier tables when HHF is reset. Fixes: 10239edf86f1 ("net-qdisc-hhf: Heavy-Hitter Filter (HHF) qdisc") Assisted-by: Codex:gpt-5.5-cyber-preview Signed-off-by: Samuel Moelius <sam.moelius@trailofbits.com> Signed-off-by: David S. Miller <davem@davemloft.net>
9 daysnet/sched: dualpi2: clear stale classification on filter missSamuel Moelius
DualPI2 leaves previous classification state attached to an skb when filter classification returns no match. The enqueue path can then act on stale state from an earlier classification attempt. A filter miss should fall back to the default class without reusing old per-packet classification data. Initialize the classification result to CLASSIC before running the classifier. Explicit L4S, priority, and successful filter classification can still override that default. Fixes: 8f9516daedd6 ("sched: Add enqueue/dequeue of dualpi2 qdisc") Assisted-by: Codex:gpt-5.5-cyber-preview Signed-off-by: Samuel Moelius <sam.moelius@trailofbits.com> Signed-off-by: David S. Miller <davem@davemloft.net>
10 daysnet/sched: act_bpf: use rcu_dereference_bh() to read the filterSechang Lim
tcf_bpf_act() can run from the tc egress path, which holds only rcu_read_lock_bh(), but reads prog->filter with rcu_dereference() and trips lockdep: WARNING: suspicious RCU usage net/sched/act_bpf.c:47 suspicious rcu_dereference_check() usage! 1 lock held by syz.2.1588/12756: #0: (rcu_read_lock_bh){....}-{1:3}, at: __dev_queue_xmit net/core/dev.c:4792 tcf_bpf_act+0x6ae/0x940 net/sched/act_bpf.c:47 tcf_classify+0x6e4/0x1080 net/sched/cls_api.c:1860 sch_handle_egress net/core/dev.c:4545 [inline] __dev_queue_xmit+0x2185/0x2c00 net/core/dev.c:4808 packet_sendmsg+0x3dfa/0x5120 net/packet/af_packet.c:3114 The other tc actions and cls_bpf already use rcu_dereference_bh() here. Do the same. Fixes: 1f211a1b929c ("net, sched: add clsact qdisc") Signed-off-by: Sechang Lim <rhkrqnwk98@gmail.com> Reviewed-by: Amery Hung <ameryhung@gmail.com> Link: https://patch.msgid.link/20260629154112.1164986-1-rhkrqnwk98@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
10 daysnet/sched: sch_teql: Introduce slaves_lock to avoid race condition and UAFJamal Hadi Salim
The teql master->slaves singly linked list is not protected against multiple writes. It can be mod'ed concurently from teql_master_xmit(), teql_dequeue(), teql_init() and teql_destroy() without holding any list lock or RCU protection. zdi-disclosures@trendmicro.com has demonstrated that the qdisc is freed after an RCU grace period, but teql_master_xmit() running on another CPU can still hold a stale pointer into the list, resulting in a slab-use-after-free: BUG: KASAN: slab-use-after-free in teql_master_xmit+0xf0f/0x16b0 Read of size 8 at addr ffff888013fb0440 by task poc/332 Freed 512-byte region [ffff888013fb0400, ffff888013fb0600) (kmalloc-512) The fix? Add a per-master slaves_lock spinlock that serializes all mutations of master->slaves and the NEXT_SLAVE() links in teql_destroy() and teql_qdisc_init(). teql_master_xmit() also takes the same slaves_lock around those updates. Annotate master->slaves and the per-slave ->next pointer with __rcu and use the appropriate RCU accessors everywhere they are touched: rcu_assign_pointer() on the writer side (under slaves_lock), rcu_dereference_protected() for the writer-side loads (also under slaves_lock), rcu_dereference_bh() for the loads in teql_master_xmit() and rtnl_dereference() for the loads in teql_master_open()/teql_master_mtu(), which run under RTNL. Pair this with rcu_read_lock_bh()/rcu_read_unlock_bh() around the list traversal in teql_master_xmit(), so that readers either observe a fully linked list or are deferred until the in-flight mutation completes. The two early-return paths in teql_master_xmit() are updated to release the RCU-bh read-side critical section before returning, since leaving it held would disable BH on that CPU for good. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: zdi-disclosures@trendmicro.com Tested-by: Victor Nogueira <victor@mojatatu.com> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Link: https://patch.msgid.link/20260628111229.669751-1-jhs@mojatatu.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
14 daysnet/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>
14 daysnet/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-23net/sched: cls_api: Handle TC_ACT_CONSUMED in tcf_qevent_handleJamal Hadi Salim
tcf_classify() can return TC_ACT_CONSUMED while the skb is held by the defragmentation engine (e.g. act_ct on out-of-order fragments). When that happens the skb is no longer owned by the caller and must not be touched again. tcf_qevent_handle() did not handle TC_ACT_CONSUMED: it fell through the switch and returned the skb to the caller as if classification had passed. The only qdisc that wires up qevents today is RED, via three call sites (qe_mark on RED_PROB_MARK/HARD_MARK, qe_early_drop on congestion_drop) red_enqueue() was continuing to operate on an skb it no longer owns in this case -- enqueueing it, dropping it, or updating statistics. Resulting in a UAF. tc qdisc add dev eth0 root handle 1: red ... qevent early_drop block 10 tc filter add block 10 ... action ct (with ct defrag enabled and traffic that produces out-of-order fragments, e.g. a fragmented UDP stream) Handle TC_ACT_CONSUMED in tcf_qevent_handle() the same way the ingress and egress fast paths do: treat it as stolen and return NULL without touching the skb. Unlike the TC_ACT_STOLEN case, the skb must not be dropped/freed here, as it is no longer owned by us. Fixes: 3f14b377d01d ("net/sched: act_ct: fix skb leak and crash on ooo frags") Reported-by: Zero Day Initiative <zdi-disclosures@trendmicro.com> Tested-by: Victor Nogueira <victor@mojatatu.com> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Link: https://patch.msgid.link/20260620130749.226642-1-jhs@mojatatu.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-23net: do not acquire dev->tx_global_lock in netdev_watchdog_up()Eric Dumazet
Marek Szyprowski reported a deadlock during system resume when virtio_net driver is used. The deadlock occurs because netif_device_attach() is called while holding dev->tx_global_lock (via netif_tx_lock_bh() in virtnet_restore_up()). netif_device_attach() calls __netdev_watchdog_up(), which now also tries to acquire dev->tx_global_lock to synchronize with dev_watchdog(). This recursive lock acquisition results in a deadlock. Fix this by removing the tx_global_lock acquisition from netdev_watchdog_up(). The critical state (watchdog_timer and watchdog_ref_held) is already protected by dev->watchdog_lock, which was introduced in the blamed commit. Fixes: 8eed5519e496 ("net: watchdog: fix refcount tracking races") Reported-by: Marek Szyprowski <m.szyprowski@samsung.com> Closes: https://lore.kernel.org/netdev/a443376e-5187-4268-93b3-58047ef113a8@samsung.com/ Signed-off-by: Eric Dumazet <edumazet@google.com> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> Reviewed-by: Simon Horman <horms@kernel.org> Link: https://patch.msgid.link/20260622110108.69541-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-21net/sched: dualpi2: fix GSO backlog accountingXingquan Liu
When DualPI2 splits a GSO skb into N segments, it propagates N additional packets to its parent before returning NET_XMIT_SUCCESS. The parent then accounts for the original skb once more, leaving its qlen one larger than the number of packets actually queued. With QFQ as the parent, after all real packets are dequeued, QFQ still has a non-zero qlen while its in-service aggregate has no active classes. qfq_choose_next_agg() returns NULL and qfq_dequeue() passes the result to qfq_peek_skb(), causing a NULL pointer dereference. Follow the same pattern used by tbf_segment() and taprio: count only successfully queued segments, propagate the difference between the original skb and those segments, and return NET_XMIT_SUCCESS whenever at least one segment was queued. Fixes: 8f9516daedd6 ("sched: Add enqueue/dequeue of dualpi2 qdisc") Cc: stable@vger.kernel.org Signed-off-by: Xingquan Liu <b1n@b1n.io> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Reviewed-by: Victor Nogueira <victor@mojatatu.com> Link: https://patch.msgid.link/20260619151447.223640-1-b1n@b1n.io Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-21net/sched: act_ct: fix nf_connlabels leak on two error pathsMichael Bommarito
tcf_ct_fill_params() calls nf_connlabels_get() (setting put_labels) when TCA_CT_LABELS is present, but two later error sites use a bare return instead of "goto err", skipping the err: nf_connlabels_put() cleanup. They also precede the "p->put_labels = put_labels" assignment, so the tcf_ct_params_free() fallback does not release the count either. Each failed RTM_NEWACTION on these paths leaks one nf_connlabels reference: net->ct.labels_used is incremented and never released. The action is reachable with CAP_NET_ADMIN over the netns, i.e. from an unprivileged user namespace on default-userns kernels. Impact: an unprivileged user with CAP_NET_ADMIN over a network namespace (e.g. via user namespaces) leaks one nf_connlabels reference per failed RTM_NEWACTION on the two error paths; net->ct.labels_used is never released. The err: label is safe to reach from both sites: p->tmpl is still NULL there (kzalloc'd, not yet assigned) and nf_ct_put(NULL) is a no-op, so no inline release is needed. Fixes: 70f06c115bcc ("sched: act_ct: switch to per-action label counting") Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Link: https://patch.msgid.link/20260617215708.1115818-1-michael.bommarito@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-18net/sched: act_ct: preserve tc_skb_cb across defragmentationZihan Xi
tcf_ct_handle_fragments() calls nf_ct_handle_fragments() without saving and restoring skb->cb. The defrag helper clears IPCB/IP6CB, which aliases the tc_skb_cb/qdisc_skb_cb control buffer. Fragmented traffic through act_ct therefore loses qdisc metadata such as pkt_segs and can trigger WARN_ON_ONCE() in qdisc_pkt_segs() when panic_on_warn is enabled. Save and restore the full tc_skb_cb around nf_ct_handle_fragments(), matching the pattern used by ovs_ct_handle_fragments(). Fixes: ec624fe740b4 ("net/sched: Extend qdisc control block with tc control block") Cc: stable@vger.kernel.org Reported-by: Yuan Tan <yuantan098@gmail.com> Reported-by: Yifan Wu <yifanwucs@gmail.com> Reported-by: Juefei Pu <tomapufckgml@gmail.com> Reported-by: Xin Liu <bird@lzu.edu.cn> Signed-off-by: Zihan Xi <xizh2024@lzu.edu.cn> Signed-off-by: Ren Wei <n05ec@lzu.edu.cn> Link: https://patch.msgid.link/510c51217fd7aaf29c6dc298bab8d643fe229b1c.1781358692.git.xizh2024@lzu.edu.cn Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-16Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/netJakub Kicinski
Merge in late fixes in preparation for the net-next PR. Conflicts: net/tls/tls_sw.c 406e8a651a7b ("net: skmsg: preserve sg.copy across SG transforms") 79511603a65b ("tls: remove dead sockmap (psock) handling from the SW path") drivers/net/ethernet/microsoft/mana/mana_en.c f8fd56977eeea ("net: mana: guard TX wq object destroy with INVALID_MANA_HANDLE check") d07efe5a6e641 ("net: mana: Use per-queue allocation for tx_qp to reduce allocation size") https://lore.kernel.org/ajAPXu-C_PuTgV-a@sirena.org.uk No adjacent changes. Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-14net/sched: act_csum: don't mangle UDP tunnel GSO packetsAlice Mikityanska
Similar to commit add641e7dee3 ("sched: act_csum: don't mangle TCP and UDP GSO packets"), UDP tunnel GSO packets going through act_csum shouldn't have their checksum calculated at this point, because it will be done after segmentation. Setting the checksum in act_csum modifies skb->ip_summed and prevents inner IP csum offload from kicking in, resulting in a packet with a bad checksum. Add UDP tunnel GSO packets to the exceptions, and also add UDP GSO (SKB_GSO_UDP_L4), as the same logic as in the commit mentioned above applies to UDP GSO too. Signed-off-by: Alice Mikityanska <alice@isovalent.com> Reviewed-by: Davide Caratti <dcaratti@redhat.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Link: https://patch.msgid.link/20260611192955.604661-2-alice.kernel@fastmail.im Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-06-12net/sched: sch_dualpi2: Add missing module aliasVictor Nogueira
When a qdisc is added by name, the kernel tries to autoload its module via request_qdisc_module(), which calls: request_module(NET_SCH_ALIAS_PREFIX "%s", name); i.e. it asks modprobe to resolve the "net-sch-<kind>" alias (e.g. "net-sch-dualpi2") rather than the module's file name. Since dualpi2 was shipped without this alias, the autoload fails: tc qdisc add dev lo root handle 1: dualpi2 Error: Specified qdisc kind is unknown. Fix this by adding the missing alias so the qdisc is autoloaded on demand like the others. Fixes: 320d031ad6e4 ("sched: Struct definition and parsing of dualpi2 qdisc") Signed-off-by: Victor Nogueira <victor@mojatatu.com> Reviewed-by: Pedro Tammela <pctammela@mojatatu.com> Link: https://patch.msgid.link/20260611205849.3287640-1-victor@mojatatu.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-12net: watchdog: fix refcount tracking racesEric Dumazet
Blamed commit converted the untracked dev_hold()/dev_put() calls in the watchdog code to use the tracked dev_hold_track()/dev_put_track() (which were later renamed/interfaced to netdev_hold() and netdev_put()). By introducing dev->watchdog_dev_tracker to store the reference tracking information without adding synchronization between netdev_watchdog_up() and dev_watchdog(), it enabled the race condition where this pointer could be overwritten or freed concurrently, leading to the list corruption crash syzbot reported: list_del corruption, ffff888114a18c00->next is NULL kernel BUG at lib/list_debug.c:52 ! Oops: invalid opcode: 0000 [#1] SMP KASAN PTI CPU: 1 UID: 0 PID: 91 Comm: kworker/u8:5 Not tainted syzkaller #0 PREEMPT(lazy) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/09/2026 Workqueue: events_unbound linkwatch_event RIP: 0010:__list_del_entry_valid_or_report.cold+0x22/0x2a lib/list_debug.c:52 Call Trace: <TASK> __list_del_entry_valid include/linux/list.h:132 [inline] __list_del_entry include/linux/list.h:246 [inline] list_move_tail include/linux/list.h:341 [inline] ref_tracker_free+0x1a7/0x6c0 lib/ref_tracker.c:329 netdev_tracker_free include/linux/netdevice.h:4491 [inline] netdev_put include/linux/netdevice.h:4508 [inline] netdev_put include/linux/netdevice.h:4504 [inline] netdev_watchdog_down net/sched/sch_generic.c:600 [inline] dev_deactivate_many+0x28c/0xfe0 net/sched/sch_generic.c:1363 dev_deactivate+0x109/0x1d0 net/sched/sch_generic.c:1397 linkwatch_do_dev net/core/link_watch.c:184 [inline] linkwatch_do_dev+0xd3/0x120 net/core/link_watch.c:166 __linkwatch_run_queue+0x3a5/0x810 net/core/link_watch.c:240 linkwatch_event+0x8f/0xc0 net/core/link_watch.c:314 process_one_work+0xa0e/0x1980 kernel/workqueue.c:3314 process_scheduled_works kernel/workqueue.c:3397 [inline] worker_thread+0x5ef/0xe50 kernel/workqueue.c:3478 kthread+0x370/0x450 kernel/kthread.c:436 ret_from_fork+0x69a/0xc80 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 This patch has three coordinated parts: 1) Add dev->watchdog_lock and dev->watchdog_ref_held to serialize watchdog operations. 2) Remove netdev_watchdog_up() call from netif_carrier_on(): This ensures netdev_watchdog_up() is only called from process/BH context (via linkwatch workqueue dev_activate()), allowing us to use spin_lock_bh() for synchronization. 3) Synchronize watchdog up and watchdog timer: Protect netdev_watchdog_up() with tx_global_lock and watchdog_lock. Only allocate a new tracker in netdev_watchdog_up() if one is not already present. In dev_watchdog(), ensure we don't release the tracker if the timer was rescheduled either by dev_watchdog() itself or concurrently by netdev_watchdog_up(). Fixes: f12bf6f3f942 ("net: watchdog: add net device refcount tracker") Reported-by: syzbot+381d82bbf0253710b35d@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/6a26b751.c25708ab.1b19ef.0013.GAE@google.com/T/#u Tested-by: syzbot+3479efbc2821cb2a79f2@syzkaller.appspotmail.com Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260611152737.2580480-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-12net/sched: sch_dualpi2: Do not call qdisc_tree_reduce_backlog during peek ↵Victor Nogueira
before restoring qlen Whenever dualpi2 drops packets during peek, it calls qdisc_tree_reduce_backlog. An issue arises because it calls qdisc_tree_reduce_backlog before it reincrements the qlen. If qlen drops to zero, but peek returns an skb, the parent's qlen_notify callback will be executed even though dualpi2 still has 1 packet on the queue and, thus, mistakenly deactivates the parent's class which leads to a null-ptr-deref: [ 101.427314][ T599] Oops: general protection fault, probably for non-canonical address 0xdffffc0000000009: 0000 [#1] SMP KASAN NOPTI [ 101.427755][ T599] KASAN: null-ptr-deref in range [0x0000000000000048-0x000000000000004f] [ 101.428048][ T599] CPU: 2 UID: 0 PID: 599 Comm: ping Not tainted 7.1.0-rc5-00284-gbce53c430ed7 #102 PREEMPT(full) [ 101.428400][ T599] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 101.428608][ T599] RIP: 0010:qfq_dequeue (net/sched/sch_qfq.c:1150) sch_qfq [ 101.428821][ T599] Code: 00 fc ff df 80 3c 02 00 0f 85 46 0c 00 00 4c 8d 73 48 48 89 9d b8 02 00 00 48 b8 00 00 00 00 00 fc ff df 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 2d 0c 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b All code [ 101.429348][ T599] RSP: 0018:ffff8881110df4f0 EFLAGS: 00010216 [ 101.429541][ T599] RAX: dffffc0000000000 RBX: 0000000000000000 RCX: dffffc0000000000 [ 101.429763][ T599] RDX: 0000000000000009 RSI: 00000024c0000000 RDI: ffff88811436c2b0 [ 101.429985][ T599] RBP: ffff88811436c000 R08: ffff88811436c280 R09: 1ffff11021277523 [ 101.430206][ T599] R10: 1ffff11021277526 R11: 1ffff11021277527 R12: 00000024c0000000 [ 101.430423][ T599] R13: ffff88811436c2b8 R14: 0000000000000048 R15: 0000000020000000 [ 101.430642][ T599] FS: 00007f61813e1c40(0000) GS:ffff8881691ef000(0000) knlGS:0000000000000000 [ 101.430913][ T599] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 101.431100][ T599] CR2: 00005651650850a8 CR3: 000000010ca0b000 CR4: 0000000000750ef0 [ 101.431320][ T599] PKRU: 55555554 [ 101.431433][ T599] Call Trace: [ 101.431544][ T599] <TASK> [ 101.431628][ T599] __qdisc_run (net/sched/sch_generic.c:322 net/sched/sch_generic.c:427 net/sched/sch_generic.c:445) [ 101.431792][ T599] ? dev_qdisc_enqueue (./include/trace/events/qdisc.h:49 (discriminator 22) net/core/dev.c:4176 (discriminator 22)) [ 101.431941][ T599] __dev_queue_xmit (./include/net/pkt_sched.h:120 ./include/net/pkt_sched.h:117 net/core/dev.c:4292 net/core/dev.c:4831) Fix this by only calling qdisc_tree_reduce_backlog in peek after the qlen is restored. Fixes: 8f9516daedd6 ("sched: Add enqueue/dequeue of dualpi2 qdisc") Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Victor Nogueira <victor@mojatatu.com> Link: https://patch.msgid.link/20260610192855.3121513-4-victor@mojatatu.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-12net/sched: sch_codel: Do not call qdisc_tree_reduce_backlog during peek ↵Victor Nogueira
before restoring qlen Whenever codel drops packets during peek, it calls qdisc_tree_reduce_backlog. An issue arises because it calls qdisc_tree_reduce_backlog before it reincrements the qlen. If qlen drops to zero, but peek returns an skb, the parent's qlen_notify callback will be executed even though codel still has 1 packet on the queue and, thus, will mistakenly deactivate the parent's class causing issues like a wild memory access when qfq has codel as a child: [ 36.339843][ T370] Oops: general protection fault, probably for non-canonical address 0xfbd59c0000000024: 0000 [#1] SMP KASAN NOPTI [ 36.340408][ T370] KASAN: maybe wild-memory-access in range [0xdead000000000120-0xdead000000000127] [ 36.340737][ T370] CPU: 2 UID: 0 PID: 370 Comm: tc Not tainted 7.1.0-rc5-00287-g66e13b626592 #87 PREEMPT(full) [ 36.341113][ T370] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 36.341357][ T370] RIP: 0010:qfq_deactivate_agg (include/linux/list.h:1029 (discriminator 2) include/linux/list.h:1043 (discriminator 2) net/sched/sch_qfq.c:1369 (discriminator 2) net/sched/sch_qfq.c:1395 (discriminator 2)) sch_qfq [ 36.342221][ T370] RSP: 0018:ffff8881100ef370 EFLAGS: 00010216 [ 36.342422][ T370] RAX: 0000000000000000 RBX: ffff8881058a9568 RCX: dffffc0000000000 [ 36.342664][ T370] RDX: 1ffff11021064dc3 RSI: ffff888108326e00 RDI: dffffc0000000000 [ 36.342905][ T370] RBP: ffff8881058a8280 R08: dead000000000122 R09: 1bd5a00000000024 [ 36.343140][ T370] R10: fffffbfff2940329 R11: fffffbfff2940329 R12: 0000000000000000 [ 36.343383][ T370] R13: dead000000000100 R14: ffff8881058a9580 R15: ffff8881058a9578 [ 36.343631][ T370] FS: 00007fc04b0ca780(0000) GS:ffff888184fef000(0000) knlGS:0000000000000000 [ 36.343911][ T370] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 36.344116][ T370] CR2: 0000557c02c02000 CR3: 000000010e0ba000 CR4: 0000000000750ef0 [ 36.344359][ T370] PKRU: 55555554 [ 36.344481][ T370] Call Trace: ... [ 36.345054][ T370] qfq_reset_qdisc (net/sched/sch_qfq.c:357 net/sched/sch_qfq.c:1487) sch_qfq [ 36.345222][ T370] qdisc_reset (net/sched/sch_generic.c:1057) [ 36.345503][ T370] __qdisc_destroy (net/sched/sch_generic.c:1096) [ 36.345677][ T370] qdisc_graft (net/sched/sch_api.c:1062 net/sched/sch_api.c:1053 net/sched/sch_api.c:1159) [ 36.346335][ T370] tc_get_qdisc (net/sched/sch_api.c:1528 net/sched/sch_api.c:1556) Fix this by only calling qdisc_tree_reduce_backlog in peek after the qlen is restored. Fixes: 342debc12183 ("codel: remove sch->q.qlen check before qdisc_tree_reduce_backlog()") Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Victor Nogueira <victor@mojatatu.com> Link: https://patch.msgid.link/20260610192855.3121513-3-victor@mojatatu.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-12net/sched: sch_fq_codel: Do not call qdisc_tree_reduce_backlog during peek ↵Victor Nogueira
before restoring qlen Whenever fq_codel drops packets during peek, it calls qdisc_tree_reduce_backlog. An issue arises because it calls qdisc_tree_reduce_backlog before it reincrements the qlen. If qlen drops to zero, but peek returns an skb, the parent's qlen_notify callback will be executed even though fq_codel still has 1 packet on the queue and, thus, will mistakenly deactivate the parent's class causing issues like a recent report [1] and a wild memory access in qfq: [ 29.371146][ T360] Oops: general protection fault, probably for non-canonical address 0xfbd59c0000000024: 0000 [#1] SMP KASAN NOPTI [ 29.371666][ T360] KASAN: maybe wild-memory-access in range [0xdead000000000120-0xdead000000000127] [ 29.371987][ T360] CPU: 6 UID: 0 PID: 360 Comm: tc Not tainted 7.1.0-rc5-00285-gc530e5b2dbc6-dirty #82 PREEMPT(full) [ 29.372384][ T360] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 29.372620][ T360] RIP: 0010:qfq_deactivate_agg (include/linux/list.h:1029 (discriminator 2) include/linux/list.h:1043 (discriminator 2) net/sched/sch_qfq.c:1369 (discriminator 2) net/sched/sch_qfq.c:1395 (discriminator 2)) sch_qfq [ 29.373544][ T360] RSP: 0018:ffff888102417370 EFLAGS: 00010216 [ 29.373800][ T360] RAX: 0000000000000000 RBX: ffff88811224d568 RCX: dffffc0000000000 [ 29.374079][ T360] RDX: 1ffff11021fe1543 RSI: ffff88810ff0aa00 RDI: dffffc0000000000 [ 29.374368][ T360] RBP: ffff88811224c280 R08: dead000000000122 R09: 1bd5a00000000024 [ 29.374649][ T360] R10: fffffbfff7940329 R11: fffffbfff7940329 R12: 0000000000000000 [ 29.374926][ T360] R13: dead000000000100 R14: ffff88811224d580 R15: ffff88811224d578 [ 29.375207][ T360] FS: 00007f5b794e5780(0000) GS:ffff88815d1e9000(0000) knlGS:0000000000000000 [ 29.375545][ T360] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 29.375823][ T360] CR2: 000055ffb091f000 CR3: 000000010a305000 CR4: 0000000000750ef0 [ 29.376103][ T360] PKRU: 55555554 [ 29.376258][ T360] Call Trace: [ 29.376401][ T360] <TASK> ... [ 29.376885][ T360] qfq_reset_qdisc (net/sched/sch_qfq.c:357 net/sched/sch_qfq.c:1487) sch_qfq [ 29.377074][ T360] qdisc_reset (net/sched/sch_generic.c:1057) [ 29.377414][ T360] __qdisc_destroy (net/sched/sch_generic.c:1096) [ 29.377600][ T360] qdisc_graft (net/sched/sch_api.c:1062 net/sched/sch_api.c:1053 net/sched/sch_api.c:1159) [ 29.378593][ T360] tc_get_qdisc (net/sched/sch_api.c:1528 net/sched/sch_api.c:1556) Fix this by only calling qdisc_tree_reduce_backlog in peek after the qlen is restored. [1] http://lore.kernel.org/netdev/CAN2cbVe79oj0O9==m4+4x3v+O+qzRagA=2=wkrp9i9=CqYvyZA@mail.gmail.com/ Fixes: 342debc12183 ("codel: remove sch->q.qlen check before qdisc_tree_reduce_backlog()") Reported-by: Anirudh Gupta <anirudhrudr@gmail.com> Closes: https://lore.kernel.org/netdev/CAN2cbVe79oj0O9==m4+4x3v+O+qzRagA=2=wkrp9i9=CqYvyZA@mail.gmail.com/ Tested-by: Anirudh Gupta <anirudhrudr@gmail.com> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Victor Nogueira <victor@mojatatu.com> Link: https://patch.msgid.link/20260610192855.3121513-2-victor@mojatatu.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-12net/sched: act_pedit: require matching IPv4 L4 protocolSamuel Moelius
The extended IPv4 L4 header mode in act_pedit can select TCP or UDP header fields without confirming that the IPv4 protocol field matches the selected transport header. That lets a rule written for TCP or UDP modify unrelated payload bytes in a packet carrying a different protocol. Verify that the IPv4 header is long enough, that the protocol matches the selected TCP or UDP header, and that the packet is not a non-initial fragment before applying TCP or UDP extended header edits. Cc: stable+noautosel@kernel.org # in real rule sets the match confirms this before calling the action Signed-off-by: Samuel Moelius <sam.moelius@trailofbits.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-11net/sched: sch_hfsc: Don't make class passive twiceVictor Nogueira
update_vf() is called from two places for the same class during a single dequeue when the class's child qdisc (e.g. codel/fq_codel) drops its last packets while dequeuing: 1. The child calls qdisc_tree_reduce_backlog(), which, now that the child is empty, invokes hfsc_qlen_notify() -> update_vf(cl, 0, 0) and turns the class passive (cl_nactive is decremented up the hierarchy). 2. hfsc_dequeue() then calls update_vf(cl, qdisc_pkt_len(skb), cur_time) to charge the dequeued bytes. On the second call the class is already passive, but its child qdisc is still empty, so update_vf() arms go_passive again: if (cl->qdisc->q.qlen == 0 && cl->cl_flags & HFSC_FSC) go_passive = 1; The leaf is then skipped by the cl_nactive == 0 check inside the loop, which does not clear go_passive, so the stale go_passive propagates to the parent and decrements its cl_nactive a second time. A parent that still has other active children is driven to cl_nactive == 0 and removed from the vttree, even though those siblings are still backlogged. They are never dequeued again and the qdisc stalls. Fix this by only arming go_passive when the class is actually active, so an already-passive class no longer triggers a second passive transition. The byte accounting (cl->cl_total += len) still runs for every ancestor, so dequeued bytes continue to be counted exactly once. Fixes: 51eb3b65544c ("sch_hfsc: make hfsc_qlen_notify() idempotent") Reported-by: Anirudh Gupta <anirudhrudr@gmail.com> Closes: https://lore.kernel.org/netdev/CAN2cbVe79oj0O9==m4+4x3v+O+qzRagA=2=wkrp9i9=CqYvyZA@mail.gmail.com/ Tested-by: Anirudh Gupta <anirudhrudr@gmail.com> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Victor Nogueira <victor@mojatatu.com> Link: https://patch.msgid.link/20260610132824.3027549-1-victor@mojatatu.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-11net/sched: cls_flow: Dont expose folded kernel pointersJamal Hadi Salim
The flow classifier falls back to addr_fold() for fields that are missing from packet headers. In map mode, userspace controls mask, xor, rshift, addend and divisor, and can observe the resulting classid through class statistics. This allows a tc classifier in a user/network namespace to recover the 32-bit folded value of skb->sk, skb_dst() or skb_nfct(). Align with standard kernel practices for pointer hashing and replace the XOR folding with a keyed siphash (which is cryptographically secure) Fixes: e5dfb815181f ("[NET_SCHED]: Add flow classifier") Reported-by: Kyle Zeng <kylebot@openai.com> Tested-by: Kyle Zeng <kylebot@openai.com> Tested-by: Victor Nogueira <victor@mojatatu.com> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260610101839.14135-1-jhs@mojatatu.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-11net: sched: avoid printing uninitialized link speedJakub Kicinski
sch_cbs and sch_taprio print ecmd.base.speed, even if netif_get_link_ksettings() failed. When netif_get_link_ksettings() fails the ecmd may not be initialized. Use the always-initialized speed variable instead. The semantics change slightly because UNKNOWN will never be printed, but that doesn't seem important enough to complicate the code for. This is a _dbg() print, anyway. Signed-off-by: Jakub Kicinski <kuba@kernel.org> Link: https://patch.msgid.link/20260609183353.1109641-1-kuba@kernel.org Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-06-08net_sched: sch_fq: convert skb->tstamp if not monotonicWillem de Bruijn
FQ currently assumes skb->tstamp holds monotonic time, as used by TCP. Users with ns_capable CAP_NET_ADMIN can transmit skbs using SO_TXTIME with CLOCK_MONOTONIC, CLOCK_REALTIME or CLOCK_TAI clockids as of commit 80b14dee2bea ("net: Add a new socket option for a future transmit time.") More recently, skbs also gained tstamp_type to explicitly communicate the clockid of skb->tstamp, with commit 4d25ca2d6801 ("net: Rename mono_delivery_time to tstamp_type for scalabilty"), commit 1693c5db6ab8 ("net: Add additional bit to support clockid_t timestamp type") and a few others. Detect other clocks and convert to monotonic for use in FQ. That is, convert fq_skb_cb(skb)->time_to_send. Do not convert skb->tstamp itself. Network device clocks are more commonly synchronized to TAI. Conversion may be imprecise due to clock adjustment (e.g., adjfreq) between when SCM_TSTAMP is set and when it is converted in fq_enqueue. The common codepath is short, so skew will be well below common pacing operation. Even in edge cases, bursts (too soon) or beyond horizon (too late) are indistinguishable from network conditions. To which senders must be robust, as long as infrequent. Avoid overflow due to negative offsets becoming huge when converting from signed ktime_t to u64 time_to_send. Bound lower to mono 1 and upper to now + q->horizon. This protects against bad input, e.g., from BPF programs. Detect legacy BPF programs that program skb->tstamp without setting skb->tstamp_type. Here tstamp_type is zero (SKB_CLOCK_REALTIME), but the value will be unrealistic for realtime in the 21st century. Follow existing TIME_UPTIME_SEC_MAX as bound between mono and realtime. Signed-off-by: Willem de Bruijn <willemb@google.com> ---- Changes v1 -> v2 - replace Fixes tag with references inside the commit message Link: https://patch.msgid.link/20260604194221.3319080-3-willemdebruijn.kernel@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-04Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/netJakub Kicinski
Cross-merge networking fixes after downstream PR (net-7.1-rc7). Silent conflicts: net/wireless/nl80211.c cb9959ab5f99 ("wifi: cfg80211: enforce HE/EHT cap/oper consistency") a384ae969902 ("wifi: cfg80211: move AP HT/VHT/... operation to beacon info") https://lore.kernel.org/aiGJDaHV4UlCexIQ@sirena.org.uk Conflicts: drivers/net/wireless/intel/iwlwifi/mld/ap.c a342c99cb70d ("wifi: iwlwifi: mld: honor BSS_CHANGED_BEACON_ENABLED") 9bf1b409afc7 ("wifi: iwlwifi: mld: send tx power constraints before link activation") https://lore.kernel.org/ah2bfedhV45ZxMO8@sirena.org.uk drivers/net/wireless/intel/iwlwifi/pcie/drv.c 093305d801fa ("wifi: iwlwifi: pcie: simplify the resume flow if fast resume is not used") e2323929a68a ("wifi: iwlwifi: pcie: add debug print for resume flow if powered off") https://lore.kernel.org/ah2bfedhV45ZxMO8@sirena.org.uk Adjacent changes: drivers/net/ethernet/airoha/airoha_eth.c b38cae85d1c4 ("net: airoha: Fix use-after-free in metadata dst teardown") ec6c391bcca7 ("net: airoha: Introduce airoha_gdm_dev struct") drivers/net/ethernet/microchip/lan743x_main.c 8173d22b211f ("net: lan743x: permit VLAN-tagged packets up to configured MTU") e3c6508a46f5 ("net: lan743x: avoid netdev-based logging before netdev registration") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-04net: sched: don't recurse on the netdev ops lock in qdiscsJakub Kicinski
cbs_set_port_rate() and taprio_set_picos_per_byte() are reached from two paths and both already hold the device's ops lock: *_change(), via tc_modify_qdisc() which calls netdev_lock_ops(dev) before dispatching to the qdisc ops. *_dev_notifier() on NETDEV_UP / NETDEV_CHANGE, where caller holds the ops lock across the notifier chain. Switch to netif_get_link_ksettings() to avoid deadlock once __ethtool_get_link_ksettings() starts taking the netdev lock. Link: https://patch.msgid.link/20260603012840.2254293-9-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-04net/sched: fix pedit partial COW leading to page cache corruptionRajat Gupta
tcf_pedit_act() computes the COW range for skb_ensure_writable() once before the key loop using tcfp_off_max_hint, but the hint does not account for the runtime header offset added by typed keys. This can leave part of the write region un-COW'd. Fix by moving skb_ensure_writable() inside the per-key loop where the actual write offset is known, and add overflow checking on the offset arithmetic. For negative offsets (e.g. Ethernet header edits at ingress), use skb_cow() to COW the headroom instead. Guard offset_valid() against INT_MIN, where negation is undefined. Fixes: 8b796475fd78 ("net/sched: act_pedit: really ensure the skb is writable") Reported-by: Yiming Qian <yimingqian591@gmail.com> Reported-by: Keenan Dong <keenanat2000@gmail.com> Reported-by: Han Guidong <2045gemini@gmail.com> Reported-by: Zhang Cen <rollkingzzc@gmail.com> Reviewed-by: Han Guidong <2045gemini@gmail.com> Tested-by: Han Guidong <2045gemini@gmail.com> Reviewed-by: Davide Caratti <dcaratti@redhat.com> Tested-by: Davide Caratti <dcaratti@redhat.com> Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com> Tested-by: Toke Høiland-Jørgensen <toke@redhat.com> Reviewed-by: Victor Nogueira <victor@mojatatu.com> Tested-by: Victor Nogueira <victor@mojatatu.com> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Rajat Gupta <rajat.gupta@oss.qualcomm.com> Link: https://patch.msgid.link/20260531123221.48732-1-jhs@mojatatu.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-01net/sched: act_api: use RCU with deferred freeing for action lifecycleJamal Hadi Salim
When NEWTFILTER and DELFILTER are run concurrently it is possible to create a race with an associated action. Let's illustrate with CPU0 running NEWTFILTER and CPU1 running DELFILTER: 0: mutex_lock() <-- holds the idr lock 0: rcu_read_lock() 0: p = idr_find(idr, index) <-- action p is valid (RCU protects IDR) 0: mutex_unlock() <-- releases the idr lock 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held 1: idr_remove(idr, index) <-- Action removed from IDR 1: mutex_unlock() <-- mutex released allowing us to delete the action 1: tcf_action_cleanup(p); kfree(p) <-- Kfrees p immediately, no deferral 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- ouch, UAF p points to freed memory This patch fixes the race condition between NEWTFILTER and DELFILTER by adding struct rcu_head to tc_action used in the deferral and introducing a call_rcu() in the delete path to defer the final kfree(). Note: this is a revert of commit d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") but also modernization/simplification to directly use kfree_rcu(). Let's illustrate the new restored code path: 0: rcu_read_lock() 1: refcount_dec_and_mutex_lock() <-- refcnt 1->0, mutex held 1: idr_remove(idr, index) 1: mutex_unlock() 1: call_rcu(&p->tcfa_rcu, tcf_action_rcu_free) <-- defer kfree after grace period 0: p = idr_find(idr, index) 0: refcount_inc_not_zero(&p->tcfa_refcnt) <-- fails, refcnt already 0 1: rcu_read_unlock() <-- release so freeing can run after grace period After CPU1 calls idr_remove(), the object is no longer reachable through the IDR. CPU0's subsequent idr_find() will return NULL, and even if it still held a stale pointer, the immediate kfree() is now deferred until after the RCU grace period, so no UAF can occur. Fixes: d7fb60b9cafb ("net_sched: get rid of tcfa_rcu") Suggested-by: Jakub Kicinski <kuba@kernel.org> Reported-by: Kyle Zeng <kylebot@openai.com> Tested-by: Victor Nogueira <victor@mojatatu.com> Tested-by: syzbot@syzkaller.appspotmail.com Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Tested-by: Kyle Zeng <kylebot@openai.com> Reviewed-by: Pedro Tammela <pctammela@mojatatu.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Victor Nogueira <victor@mojatatu.com> Link: https://patch.msgid.link/20260531160812.68020-1-jhs@mojatatu.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-28Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/netJakub Kicinski
Cross-merge networking fixes after downstream PR (net-7.1-rc6). Conflicts: drivers/net/phy/air_en8811h.c d895767c33781 ("net: phy: air_en8811h: add AN8811HB MCU assert/deassert support") dddfadd75197e ("net: phy: Add Airoha phy library for shared code") 5226bb6634cdf ("net: phy: air_phy_lib: Factorize BuckPBus register accessors") e08f0ea6daf2e ("net: phy: Rename Airoha common BuckPBus register accessors") net/sched/sch_netem.c a2f6ed7b4873 ("net/sched: netem: add per-impairment extended statistics") 9552b11e3eda ("net/sched: fix packet loop on netem when duplicate is on") Adjacent changes: drivers/dpll/zl3073x/core.c c1224569cef0 ("dpll: zl3073x: make frequency monitor a per-device attribute") 54e65df8cf18 ("dpll: zl3073x: report FFO as DPLL vs input reference offset") net/iucv/af_iucv.c 347fdd4df85f ("af_iucv: convert to getsockopt_iter") 3589d20a666c ("net/iucv: fix locking in .getsockopt") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-28net/sched: act_mirred: Fix return code in early mirred redirect error pathsVictor Nogueira
Since retval is set as TC_ACT_STOLEN in the mirred redirect case, returning retval in cases where redirect failed will make the callers not register the skb as being dropped. Fix this by returning TC_ACT_SHOT instead in such scenarios. Fixes: 16085e48cb48 ("net/sched: act_mirred: Create function tcf_mirred_to_dev and improve readability") Reported-by: Sashiko <sashiko-bot@kernel.org> Closes: https://sashiko.dev/#/patchset/20260413082027.2244884-1-hxzene%40gmail.com Signed-off-by: Victor Nogueira <victor@mojatatu.com> Link: https://patch.msgid.link/20260525122556.973584-8-jhs@mojatatu.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-05-28net/sched: act_mirred: Fix blockcast recursion bypass leading to stack overflowKito Xu (veritas501)
tcf_mirred_act() checks sched_mirred_nest against MIRRED_NEST_LIMIT (4) to prevent deep recursion. However, when the action uses blockcast (tcfm_blockid != 0), the function returns at the tcf_blockcast() call BEFORE reaching the counter increment. As a result, the recursion counter never advances and the limit check is entirely bypassed. When two devices share a TC egress block with a mirred blockcast rule, a packet egressing on device A is mirrored to device B via blockcast; device B's egress TC re-enters tcf_mirred_act() via blockcast and mirrors back to A, creating an unbounded recursion loop: tcf_mirred_act -> tcf_blockcast -> tcf_mirred_to_dev -> dev_queue_xmit -> sch_handle_egress -> tcf_classify -> tcf_mirred_act -> (repeat) This recursion continues until the kernel stack overflows. The bug is reachable from an unprivileged user via unshare(CLONE_NEWUSER | CLONE_NEWNET): user namespaces grant CAP_NET_ADMIN in the new network namespace, which is sufficient to create dummy devices, attach clsact qdiscs with shared blocks, and install mirred blockcast filters. BUG: TASK stack guard page was hit at ffffc90000b7fff8 Oops: stack guard page: 0000 [#1] SMP KASAN NOPTI CPU: 2 UID: 1000 PID: 169 Comm: poc Not tainted 7.0.0-rc7-next-20260410 RIP: 0010:xas_find+0x17/0x480 Call Trace: xa_find+0x17b/0x1d0 tcf_mirred_act+0x640/0x1060 tcf_action_exec+0x400/0x530 basic_classify+0x128/0x1d0 tcf_classify+0xd83/0x1150 tc_run+0x328/0x620 __dev_queue_xmit+0x797/0x3100 tcf_mirred_to_dev+0x7b1/0xf70 tcf_mirred_act+0x68a/0x1060 [repeating ~30+ times until stack overflow] Kernel panic - not syncing: Fatal exception in interrupt Fix this by incrementing sched_mirred_nest before calling tcf_blockcast() and decrementing it on return, mirroring the non-blockcast path. This ensures subsequent recursive entries see the updated counter and are correctly limited by MIRRED_NEST_LIMIT. Fixes: fe946a751d9b ("net/sched: act_mirred: add loop detection") Signed-off-by: Kito Xu (veritas501) <hxzene@gmail.com> Link: https://patch.msgid.link/20260525122556.973584-7-jhs@mojatatu.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-05-28net/sched: Fix ethx:ingress -> ethy:egress -> ethx:ingress mirred loopJamal Hadi Salim
When mirred redirects to ingress (from either ingress or egress) the loop state from sched_mirred_dev array dev is lost because of 1) the packet deferral into the backlog and 2) the fact the sched_mirred_dev array is cleared. In such cases, if there was a loop we won't discover it. Here's a simple test to reproduce: ip a add dev port0 10.10.10.11/24 tc qdisc add dev port0 clsact tc filter add dev port0 egress protocol ip \ prio 10 matchall action mirred ingress redirect dev port1 tc qdisc add dev port1 clsact tc filter add dev port1 ingress protocol ip \ prio 10 matchall action mirred egress redirect dev port0 ping -c 1 -W0.01 10.10.10.10 Fixes: fe946a751d9b ("net/sched: act_mirred: add loop detection") Tested-by: Victor Nogueira <victor@mojatatu.com> Reviewed-by: Stephen Hemminger <stephen@networkplumber.org> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Link: https://patch.msgid.link/20260525122556.973584-6-jhs@mojatatu.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-05-28net/sched: fix packet loop on netem when duplicate is onJamal Hadi Salim
When netem duplicates a packet it re-enqueues the copy at the root qdisc. If another netem sits in the tree the copy can be duplicated again, recursing until the stack or memory is exhausted. The original duplication guard temporarily zeroed q->duplicate around the re-enqueue, but that does not cover all cases because it is per-qdisc state shared across all concurrent enqueue paths and is not safe without additional locking. Use the skb tc_depth field introduced in an earlier patch: - increment it on the duplicate before re-enqueue - skip duplication for any skb whose tc_depth is already non-zero. This marks the packet itself rather than mutating qdisc state, therefore it is safe regardless of tree topology or concurrency. Fixes: 0afb51e72855 ("[PKT_SCHED]: netem: reinsert for duplication") Reported-by: William Liu <will@willsroot.io> Reported-by: Savino Dicanosa <savy@syst3mfailure.io> Closes: https://lore.kernel.org/netdev/8DuRWwfqjoRDLDmBMlIfbrsZg9Gx50DHJc1ilxsEBNe2D6NMoigR_eIRIG0LOjMc3r10nUUZtArXx4oZBIdUfZQrwjcQhdinnMis_0G7VEk=@willsroot.io/ Co-developed-by: Victor Nogueira <victor@mojatatu.com> Signed-off-by: Victor Nogueira <victor@mojatatu.com> Reviewed-by: William Liu <will@willsroot.io> Reviewed-by: Stephen Hemminger <stephen@networkplumber.org> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Link: https://patch.msgid.link/20260525122556.973584-5-jhs@mojatatu.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-05-28net/sched: Revert "net/sched: Restrict conditions for adding duplicating ↵Jamal Hadi Salim
netems to qdisc tree" This reverts commit ec8e0e3d7adef940cdf9475e2352c0680189d14e. The original patch rejects any tree containing two netems when either has duplication set, even when they sit on unrelated classes of the same classful parent. That broke configurations that have worked since netem was introduced. The re-entrancy problem the original commit was trying to solve is handled by later patch using tc_depth flag. Doing this revert will (re)expose the original bug with multiple netem duplication. When this patch is backported make sure and get the full series. Fixes: ec8e0e3d7ade ("net/sched: Restrict conditions for adding duplicating netems to qdisc tree") Reported-by: Ji-Soo Chung <jschung2@proton.me> Reported-by: Gerlinde <lrGerlinde@mailfence.com> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220774 Reported-by: zyc zyc <zyc199902@zohomail.cn> Closes: https://lore.kernel.org/all/19adda5a1e2.12410b78222774.9191120410578703463@zohomail.cn/ Reported-by: Manas Ghandat <ghandatmanas@gmail.com> Closes: https://lore.kernel.org/netdev/f69b2c8f-8325-4c2e-a011-6dbc089f30e4@gmail.com/ Reviewed-by: Stephen Hemminger <stephen@networkplumber.org> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Link: https://patch.msgid.link/20260525122556.973584-3-jhs@mojatatu.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-05-27net: sch_fq: update flow delivery time on earlier EDT packetWillem de Bruijn
When inserting an EDT packet with time before flow->time_next_packet, update the flow and possibly queue next delivery time. Reinsert the flow into the q->delayed rb-tree to position correctly and to have fq_check_throttled set wake-up at the right next time. Factor RB tree insertion out fq_flow_set_throttled to avoid open coding twice. EDT packets do not take precedence over queue rate limit. Skip this new step if a queue limit is set. EDT packets do take precedence over per-socket rate limits, as can be seen from fq_dequeue reading sk_pacing_rate if !skb->tstamp. With this change the so_txtime selftest sends packets in the expected order. Signed-off-by: Willem de Bruijn <willemb@google.com> Link: https://patch.msgid.link/20260526134109.2624493-1-willemdebruijn.kernel@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-27net/sched: cls_bpf: prevent unbounded recursion in offload rollbackJiayuan Chen
Quan Sun reported [1] a stack overflow in cls_bpf_offload_cmd(). Reproducer on netdevsim: add a skip_sw cls_bpf filter, set the bpf_tc_accept debugfs knob to 0, then `tc filter replace`. The replace calls tc_setup_cb_replace() which fails. cls_bpf_offload_cmd() then swaps prog/oldprog and recursively calls itself to roll back. But bpf_tc_accept=0 makes the rollback fail too, which triggers yet another rollback frame with the same arguments, and so on until the stack is exhausted. bpf_tc_accept is just a convenient knob for the reproducer. Any driver whose tc_setup_cb_replace() fails twice in a row can hit the same loop, so this is not a netdevsim-only issue. Two ways to fix it: 1) Have the rollback call tc_setup_cb_add() on oldprog instead of re-entering cls_bpf_offload_cmd(). 2) Mark the rollback frame with a flag and skip a second-level rollback from inside it. Go with (2). It is the smaller change and keeps the original behaviour: the rollback still goes through tc_setup_cb_replace(), so the driver gets one real chance to restore its state. If that attempt also fails, we just return the original error instead of recursing. [1]: https://lore.kernel.org/bpf/ce5a6005-3c5e-4696-9e05-eba9461dc860@std.uestc.edu.cn/T/#u Fixes: 102740bd9436 ("cls_bpf: fix offload assumptions after callback conversion") Reviewed-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev> Link: https://patch.msgid.link/20260526025529.24382-1-jiayuan.chen@linux.dev Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-25net/sched: sch_ets: make cl->quantum locklessEric Dumazet
cl->quantum does not need to be protected by RTNL or qdisc spinlock. Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Victor Nogueira <victor@mojatatu.com> Link: https://patch.msgid.link/20260522110356.1403343-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-22net/sched: tbf: add extack to offload paramsDavid Yang
Drivers might have error messages to propagate to user space. Propagate the netlink extack so that they can inform user space in a verbal way of their limitations. Signed-off-by: David Yang <mmyangfl@gmail.com> Link: https://patch.msgid.link/20260521010320.208138-3-mmyangfl@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-22net/sched: prefer existing extack message in qdisc_offload_graft_helper()David Yang
Use NL_SET_ERR_MSG_WEAK so any existing error message (probably from the underlying driver) is used instead of the generic fallback. Signed-off-by: David Yang <mmyangfl@gmail.com> Link: https://patch.msgid.link/20260521010320.208138-2-mmyangfl@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-20net/sched: sch_drr: make cl->quantum locklessEric Dumazet
cl->quantum does not need to be protected by RTNL or qdisc spinlock. Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260519094618.2632073-3-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-20net/sched: sch_drr: annotate data-races around cl->deficitEric Dumazet
drr_dump_class_stats() runs without qdisc spinlock held. Add missing READ_ONCE()/WRITE_ONCE() annotations around cl->deficit. Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260519094618.2632073-2-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-19net/sched: sch_htb: fix htb_dump_class_stats() vs offload modeEric Dumazet
htb_dump_class_stats() and htb_offload_aggregate_stats() call gnet_stats_basic_sync_init(&cl->bstats) which is wrong on 32bit arches when syncp is cleared. Make sure to acquire qdisc spinlock and use _bstats_set() to ease future lockless dumps. Fixes: 83271586249c ("sch_htb: Stats for offloaded HTB") Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Maxim Mikityanskiy <maximmi@mellanox.com> Cc: Tariq Toukan <tariqt@nvidia.com> Link: https://patch.msgid.link/20260518090518.629245-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-15net/sched: sch_htb: annotate data-races (III)Eric Dumazet
htb_dump_class_stats() will soon run locklessly. (no RTNL, not qdisc spinlock). Add READ_ONCE()/WRITE_ONCE() annotations on these fields: - cl->overlimits - cl->drops - cl->tokens - cl->ctokens Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260514095935.3926276-5-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-15net/sched: sch_htb: annotate data-races (II)Eric Dumazet
htb_dump_class_stats() will soon run locklessly. (no RTNL, not qdisc spinlock). Remove cl->xstats and replace it with two fields: - xstats_lends - xstats_borrows Then use READ_ONCE()/WRITE_ONCE() annotations on them, and change htb_dump_class_stats to use a private struct tc_htb_xstats. Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260514095935.3926276-4-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-15net/sched: sch_htb: annotate data-races (I)Eric Dumazet
htb_dump() runs without holding qdisc spinlock. Add missing READ_ONCE()/WRITE_ONCE() annotations around q->overlimits and q->direct_pkts. Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260514095935.3926276-3-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-15net/sched: sch_htb: do not change sch->flags in htb_dump()Eric Dumazet
htb_dump() runs without holding qdisc spinlock. It is illegal to touch sch->flags with non locked RMW, as concurrent readers might see intermediate wrong values. Set TCQ_F_OFFLOADED in control path (htb_init()) instead. Fixes: d03b195b5aa0 ("sch_htb: Hierarchical QoS hardware offload") Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260514095935.3926276-2-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-15net/sched: sch_dualpi2: annotate data-races in dualpi2_dump_stats()Eric Dumazet
dualpi2_dump_stats() runs without qdisc lock held. Add missing READ_ONCE()/WRITE_ONCE() annotations. Fixes: d4de8bffbef4 ("sched: Dump configuration and statistics of dualpi2 qdisc") Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Vineet Agarwal <agarwal.vineet2006@gmail.com> Link: https://patch.msgid.link/20260514114713.4134674-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-05-14net/sched: sch_hfsc: annotate data-races in hfsc_dump_class_stats()Eric Dumazet
hfsc_dump_class_stats() runs without qdisc spinlock being held. Add READ_ONCE()/WRITE_ONCE() annotations around: - cl->level - cl->cl_vtperiod - cl->cl_total - cl->cl_cumul Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Toke Høiland-Jørgensen <toke@toke.dk> Link: https://patch.msgid.link/20260513080853.1383975-4-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>