linux/net/sched
Jamal Hadi Salim 729c4896ab net/sched: sch_htb: limit htb_classify inner-class filter hops
htb_classify() follows each filter-selected inner class by switching
to cl->filter_list, but never bounds the number of hops. A filter on
an inner class can point back to itself or to another inner class that
points back, creating an infinite loop in the packet classification
path with the qdisc lock held and BH disabled — a soft lockup / panic
from a single packet.

Bound the traversal with a hop counter and drop the packet with a
rate-limited warning once the bound is exceeded. The counter is
incremented at the point the inner filter chain is picked up, after the
TC_ACT_* switch has consumed the classifier verdict, so a terminal
TC_ACT_QUEUED/STOLEN/TRAP on the last permitted chain still sets *qerr
to __NET_XMIT_STOLEN and the packet is not charged as a drop by this
qdisc or its parent.

The bound is TC_HTB_MAXDEPTH, taken from HTB's own parameters rather than
from the qdisc hierarchy depth limit. Class levels run from 0 to
TC_HTB_MAXDEPTH - 1, so a traversal that strictly descends in level can
take at most TC_HTB_MAXDEPTH hops. That descent is what a sane
configuration does, but it is assumed here rather than enforced:
htb_find() resolves a classid against every class in the qdisc, so a
filter may equally select a sibling or an ancestor. The normal
root -> inner -> leaf path takes a single hop, so the bound does not
affect legitimate classification.

htb_classify() can now return NULL irrespective of CONFIG_NET_CLS_ACT,
whereas previously every NULL return sat inside that ifdef. The NULL
handler in htb_enqueue() therefore cannot stay conditional either, so
drop the ifdef around it. This matches hfsc_enqueue(), which has always
handled a NULL class unconditionally. Without it, a kernel built
without actions would dereference a NULL class instead of dropping.

Conditions to recreate the bug:
- CONFIG_NET_SCHED, CONFIG_NET_SCH_HTB, CONFIG_NET_CLS_U32,
  CONFIG_LOCKUP_DETECTOR.
- Create an HTB qdisc on a device (e.g. lo), add an inner class
  1:1 with a leaf child 1:10, install a root u32 filter selecting
  1:1, and an inner-class u32 filter on 1:1 also selecting 1:1.
- Send one packet (ping). On the unfixed kernel the classify loop
  spins with the qdisc lock held; with softlockup_panic=1 it panics.
- Reachable from unprivileged user via unshare -Urn (CAP_NET_ADMIN).

Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Reported-by: Vega <vega@nebusec.ai>
Co-developed-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-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/20260826143339.271935-1-victor@mojatatu.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-08-27 12:47:58 -07:00
..
act_api.c net/sched: add get_fill_size callbacks for actions missing them 2026-08-20 12:16:43 -07:00
act_bpf.c net/sched: add get_fill_size callbacks for actions missing them 2026-08-20 12:16:43 -07:00
act_connmark.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
act_csum.c net: Use helpers to get/set UDP len tree-wide 2026-07-22 13:47:02 +02:00
act_ct.c net/sched: add get_fill_size callbacks for actions missing them 2026-08-20 12:16:43 -07:00
act_ctinfo.c net/sched: add get_fill_size callbacks for actions missing them 2026-08-20 12:16:43 -07:00
act_gact.c net/sched: act_gact, act_police: range check the fallback control action 2026-08-10 16:00:19 -07:00
act_gate.c net/sched: act_gate: snapshot parameters with RCU on replace 2026-02-27 16:10:36 -08:00
act_ife.c net/sched: act_ife: Only operate on Ethernet frames 2026-08-24 11:59:59 -07:00
act_meta_mark.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 152 2019-05-30 11:26:32 -07:00
act_meta_skbprio.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 152 2019-05-30 11:26:32 -07:00
act_meta_skbtcindex.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 152 2019-05-30 11:26:32 -07:00
act_mirred.c net/sched: act_mirred: Fix return code in early mirred redirect error paths 2026-05-28 12:26:36 +02:00
act_mpls.c net/sched: add qstats_cpu_drop_inc() helper 2026-05-04 18:59:07 -07:00
act_nat.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
act_pedit.c net/sched: add get_fill_size callbacks for actions missing them 2026-08-20 12:16:43 -07:00
act_police.c net/sched: add get_fill_size callbacks for actions missing them 2026-08-20 12:16:43 -07:00
act_sample.c net/sched: add get_fill_size callbacks for actions missing them 2026-08-20 12:16:43 -07:00
act_simple.c net/sched: Remove redundant memset(0) call in reset_policy() 2025-08-12 17:13:29 -07:00
act_skbedit.c net/sched: add qstats_cpu_drop_inc() helper 2026-05-04 18:59:07 -07:00
act_skbmod.c net/sched: act_skbmod: fix length calculations and avoid invalid header warnings 2026-08-25 11:04:12 +02:00
act_tunnel_key.c net/sched: add get_fill_size callbacks for actions missing them 2026-08-20 12:16:43 -07:00
act_vlan.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
bpf_qdisc.c bpf: net_sched: Use the correct destructor kfunc type 2026-01-12 18:53:57 -08:00
cls_api.c net/sched: account classifier filter allocations to memcg 2026-08-22 13:02:32 -07:00
cls_basic.c net/sched: account classifier filter allocations to memcg 2026-08-22 13:02:32 -07:00
cls_bpf.c net/sched: account classifier filter allocations to memcg 2026-08-22 13:02:32 -07:00
cls_cgroup.c net/sched: account classifier filter allocations to memcg 2026-08-22 13:02:32 -07:00
cls_flow.c net/sched: account classifier filter allocations to memcg 2026-08-22 13:02:32 -07:00
cls_flower.c net/sched: account classifier filter allocations to memcg 2026-08-22 13:02:32 -07:00
cls_fw.c net/sched: account classifier filter allocations to memcg 2026-08-22 13:02:32 -07:00
cls_matchall.c net/sched: account classifier filter allocations to memcg 2026-08-22 13:02:32 -07:00
cls_route.c net/sched: account classifier filter allocations to memcg 2026-08-22 13:02:32 -07:00
cls_u32.c net/sched: account classifier filter allocations to memcg 2026-08-22 13:02:32 -07:00
em_canid.c net/sched: em_canid: fix uninit-value in em_canid_match 2025-11-26 16:28:10 +01:00
em_cmp.c net: sched: fix TCF_LAYER_TRANSPORT handling in tcf_get_base_ptr() 2025-11-24 18:53:14 -08:00
em_ipset.c sched: consistently handle layer3 header accesses in the presence of VLANs 2020-07-03 14:34:53 -07:00
em_ipt.c sched: consistently handle layer3 header accesses in the presence of VLANs 2020-07-03 14:34:53 -07:00
em_meta.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
em_nbyte.c net: sched: fix TCF_LAYER_TRANSPORT handling in tcf_get_base_ptr() 2025-11-24 18:53:14 -08:00
em_text.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
em_u32.c net: fill in MODULE_DESCRIPTION()s for net/sched 2024-02-09 14:12:02 -08:00
ematch.c net_sched: reject TCF_EM_SIMPLE case for complex ematch module 2022-12-19 09:43:18 +00:00
Kconfig sched: Add enqueue/dequeue of dualpi2 qdisc 2025-07-23 17:52:07 -07:00
Makefile sched: Add enqueue/dequeue of dualpi2 qdisc 2025-07-23 17:52:07 -07:00
sch_api.c net/sched: bound qdisc_pkt_len to prevent qdisc soft lockup 2026-08-27 12:12:36 -07:00
sch_blackhole.c Revert "net: sched: Pass root lock to Qdisc_ops.enqueue" 2020-07-16 16:48:34 -07:00
sch_cake.c net/sched: sch_cake: fix autorate reconfiguration throttling 2026-08-22 13:51:40 -07:00
sch_cbs.c net: sched: avoid printing uninitialized link speed 2026-06-11 15:44:55 +02:00
sch_choke.c net/sched: add qdisc_qlen_inc() and qdisc_qlen_dec() 2026-05-11 18:28:07 -07:00
sch_codel.c net/sched: sch_codel: clamp default mtu to avoid disabling CoDel 2026-08-25 13:09:32 +02:00
sch_drr.c net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains 2026-07-20 18:16:43 -07:00
sch_dualpi2.c net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains 2026-07-20 18:16:43 -07:00
sch_etf.c net/sched: add qdisc_qlen_inc() and qdisc_qlen_dec() 2026-05-11 18:28:07 -07:00
sch_ets.c net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains 2026-07-20 18:16:43 -07:00
sch_fifo.c net: sched: fix 32-bit backlog wrap in gred, bfifo and plug enqueue 2026-08-20 13:28:45 -07:00
sch_fq_codel.c net/sched: fq_codel: clamp default quantum and mtu 2026-08-25 13:09:32 +02:00
sch_fq_pie.c net/sched: fq_pie: clamp default quantum to avoid signed overflow 2026-08-25 13:09:32 +02:00
sch_fq.c net/sched: fq: add overflow bounds to quantum and initial quantum 2026-08-25 13:09:32 +02:00
sch_frag.c net: convert remaining ipv6_stub users to direct function calls 2026-03-29 11:21:23 -07:00
sch_generic.c net: fix spurious TX timeout after dev_activate() 2026-08-27 10:25:59 +02:00
sch_gred.c net: sched: fix 32-bit backlog wrap in gred, bfifo and plug enqueue 2026-08-20 13:28:45 -07:00
sch_hfsc.c net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains 2026-07-20 18:16:43 -07:00
sch_hhf.c net/sched: hhf: clamp quantum before hhf_change() to avoid overflow 2026-08-25 13:09:32 +02:00
sch_htb.c net/sched: sch_htb: limit htb_classify inner-class filter hops 2026-08-27 12:47:58 -07:00
sch_ingress.c clsact: Fix use-after-free in init/destroy rollback asymmetry 2026-03-17 12:09:16 +01:00
sch_mq.c net/sched: mq: no longer acquire qdisc spinlocks in dump operations 2026-05-11 18:28:08 -07:00
sch_mqprio_lib.c net: add READ_ONCE()/WRITE_ONCE() annotations for dev->prio_tc_map 2026-08-17 10:27:48 -07:00
sch_mqprio_lib.h net/sched: mqprio: allow per-TC user input of FP adminStatus 2023-04-13 22:22:10 -07:00
sch_mqprio.c net: prevent torn reads in netdev_tc_txq 2026-08-17 10:27:48 -07:00
sch_multiq.c net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains 2026-07-20 18:16:43 -07:00
sch_netem.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net 2026-05-28 14:02:21 -07:00
sch_pie.c net/sched: sch_pie: annotate more data-races in pie_dump_stats() 2026-05-01 17:54:57 -07:00
sch_plug.c net: sched: fix 32-bit backlog wrap in gred, bfifo and plug enqueue 2026-08-20 13:28:45 -07:00
sch_prio.c net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains 2026-07-20 18:16:43 -07:00
sch_qfq.c net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains 2026-07-20 18:16:43 -07:00
sch_red.c net/sched: annotate data-races around sch->qstats.backlog 2026-05-11 18:28:07 -07:00
sch_sfb.c net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains 2026-07-20 18:16:43 -07:00
sch_sfq.c net/sched: sfq: clamp quantum to avoid signed overflow soft lockup 2026-08-25 13:09:32 +02:00
sch_skbprio.c net/sched: add qdisc_qlen_inc() and qdisc_qlen_dec() 2026-05-11 18:28:07 -07:00
sch_taprio.c net: add READ_ONCE()/WRITE_ONCE() annotations for dev->prio_tc_map 2026-08-17 10:27:48 -07:00
sch_tbf.c net/sched: tbf: add extack to offload params 2026-05-22 17:23:37 -07:00
sch_teql.c net/sched: sch_teql: restore skb->dev on the slave failure path 2026-08-25 15:24:35 +02:00