Linux Kernel — qdisc Rate-Table Race Condition Local Privilege Escalation (CVE-2026-68138)
Published: 2026-08-15 • Researcher: A. Ramos (aramosf), discovery by Aldo Ariel Panzardo
- Severity
- High
- CVE
- CVE-2026-68138
- Category
- binary
- Affected product
- Linux kernel, traffic-control qdisc rate-table subsystem (qdisc_get_rtab / qdisc_put_rtab)
- Affected versions
- Linux 5.1 through 7.1.5; Linux 7.2-rc1 through 7.2-rc4
- Disclosed
- 2026-08-15
- Patch status
- Patched
Tags
References
- https://raw.githubusercontent.com/CVEProject/cvelistV5/main/cves/2026/68xxx/CVE-2026-68138.json
- https://git.kernel.org/stable/c/fb29e1b41052488ee3f2d115d4a870497ebd7f7d
- https://git.kernel.org/stable/c/f43ee0c0730d6191629b5ee1ceae27b1ebfdc047
- https://github.com/aramosf/CVE-2026-68138
- https://ubuntu.com/security/cves?q=CVE-2026-68138
Archive entry
intelseclab/poc-archiveOn this page
Metadata
| Field | Value |
|---|---|
| Date Added | 2026-08-15 |
| Last Updated | 2026-08-15 |
| Author / Researcher | A. Ramos (aramosf), discovery by Aldo Ariel Panzardo |
| CVE / Advisory | CVE-2026-68138 |
| Category | binary |
| Severity | High |
| CVSS Score | 7.8 (estimated, local LPE) |
| Status | Patched |
| Tags | linux, kernel, lpe, race-condition, use-after-free, qdisc, traffic-control, flower, bpf, pipe, page-cache, modprobe, CWE-362, CWE-416, CVE-2026-68138 |
| Related |
Affected Target
| Field | Value |
|---|---|
| Software / System | Linux kernel, traffic-control qdisc rate-table subsystem (qdisc_get_rtab / qdisc_put_rtab) |
| Versions Affected | Linux 5.1 through 7.1.5; Linux 7.2-rc1 through 7.2-rc4 |
| Language / Platform | C (exploit), targets x86-64 Linux with unprivileged user namespaces |
| Authentication Required | Local unprivileged user (UID 1000) |
| Network Access Required | None – local privilege escalation |
Summary
CVE-2026-68138 is a race condition in the Linux kernel traffic-control rate-table code that leads to a use-after-free or double-free of struct qdisc_rate_table. The flower classifier sets TCF_PROTO_OPS_DOIT_UNLOCKED, allowing RTM_NEWTFILTER requests to reach qdisc_get_rtab() and qdisc_put_rtab() without holding RTNL. Concurrent requests using the same rate table race the global list and reference count, producing a UAF of a 1056-byte object in kmalloc-2k.
The exploit chains: qdisc race to create a BPF filter alias, classic-BPF SO_GET_FILTER leak to detect the alias, pipe-buffer reclaim to leak kernel page and ops pointers, simple_xattr spray to forge a mergeable pipe buffer with PIPE_BUF_FLAG_CAN_MERGE, page-cache overwrite of /sbin/modprobe ELF entry point, and module autoload trigger via AF_INET protocol 253 to execute the overwritten modprobe as initial-namespace root.
Vulnerability Details
Root Cause
qdisc_get_rtab() and qdisc_put_rtab() manage a global singly linked list (qdisc_rtab_list) and a plain int refcnt. Historically callers held the RTNL mutex, but the flower classifier’s TCF_PROTO_OPS_DOIT_UNLOCKED flag allows the police action path to call these helpers without RTNL:
tc_new_tfilter() -> fl_change() -> tcf_exts_validate_ex()
-> tcf_action_init() -> tcf_police_init()
-> qdisc_get_rtab() / qdisc_put_rtab()Because the list is global (not per-network-namespace), requests from separate network namespaces still race the same object.
Exploitation Process
- Race: Four worker threads in separate network namespaces create flower filters with police actions. Three take the success path; one supplies an invalid estimator after acquiring rate-table references, forcing cleanup and creating the race window.
- BPF reclaim: After each netlink request, a 133-instruction classic-BPF filter is attached. Its 1064-byte instruction array reclaims the freed rate-table slot.
SO_GET_FILTERdetects when two sockets share the same BPF buffer. - Pipe leak: Closing one owner frees the BPF buffer after RCU. 32-slot pipe rings reclaim it. Reading the other socket via
SO_GET_FILTERdiscloses livepipe_bufferpage and ops pointers. - Page-cache overwrite:
simple_xattrspray reclaims the freed pipe ring with a forgedpipe_bufferwithCAN_MERGEset. Writing to candidate pipes appends bytes to the/sbin/modprobepage-cache page. - Root shell:
socket(AF_INET, SOCK_DGRAM, 253)triggers module autoload, executing the overwritten modprobe as initial-namespace root.
Impact
Local privilege escalation from UID 1000 to root in the initial user namespace. Validated on QEMU lab and Ubuntu 22.04.5 (5.15.0-187-generic).
Environment / Lab Setup
| |
Proof of Concept
See
exploit.c(960 lines, C) in this folder – mirrored byte-for-byte from aramosf/CVE-2026-68138. The upstream README is preserved asupstream-README.md. The Ubuntu-specific variant is inubuntu/.
Step-by-Step Reproduction
- Boot a vulnerable kernel in QEMU with 4 vCPUs and
nokaslr(for debugging). - Build the exploit:
./build.sh - Copy to guest via 9p share at
/exploit/CVE-2026-68138. - Run as unprivileged user:
/exploit/CVE-2026-68138 - On miss: Reboot the VM before retrying (global qdisc list may be corrupted).
Expected Output
[*] CVE-2026-68138 BPF/qdisc overlap, outer uid=1000
[+] qdisc race with successful flower filters and rotating same-CPU kmalloc-2k reclaim
[+] confirmed dangling orig_prog->filter pointer
[+] pipe leak: page=<kernel pointer> ops=<kernel pointer> off=0x60f len=1 flags=0
[+] page-cache overwrite via dangling pipe
[+] controlled page-cache write confirmed; triggering helper
[+] CVE-2026-68138 initial-namespace root shell
uid=0(root) gid=0(root) groups=0(root)
[+] ROOT PROOF: uid=0(root) gid=0(root) groups=0(root)Detection and Indicators of Compromise
Remediation
| Action | Detail |
|---|---|
| Patch | Update to Linux 7.1.6+ or 7.2-rc5+. Stable fix: fb29e1b41052. Mainline fix: f43ee0c0730d. The fix adds a spinlock (qdisc_rtab_lock) to serialize rate-table list and refcount operations. |
| Workaround | Disable unprivileged user namespaces (sysctl kernel.unprivileged_userns_clone=0) to prevent the exploit from creating isolated network namespaces for the race. |
| Verification | Check if either fixing commit is present in the kernel source. The PoC returns exit code 2 (“no BPF alias found”) against fixed kernels. |
References
Notes
Verified this session by reading the full exploit source (exploit.c, 960 lines), the Ubuntu variant, build scripts, QEMU lab setup, and README. The exploit is a single statically-linked C binary using standard Linux syscalls (netlink, setsockopt, splice, pipe, xattr, socket). The embedded inline assembly is a minimal /bin/sh -c shellcode that writes a proof file and opens a root shell on the QEMU serial console.
Malware screen – clean. No obfuscation, no remote downloaders, no credential exfiltration, no miners, no persistence mechanisms. All operations are local kernel exploitation via standard syscalls. No committed binaries – pure C source.
Author: A. Ramos (aramosf, @aramosf) is a well-known security researcher. Discovery credited to Aldo Ariel Panzardo. The repo has 18 stars, includes a detailed README with affected version table, Ubuntu-specific variant with full QEMU lab instructions, and sanitized output transcripts.