PoC Archive PoC Archive
CVE-2026-68138 category: binary CVSS 7.8 (HIGH)
Patched

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

Target software 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
Status Patched
Severity High · CVSS 7.8
On this page

Metadata

FieldValue
Date Added2026-08-15
Last Updated2026-08-15
Author / ResearcherA. Ramos (aramosf), discovery by Aldo Ariel Panzardo
CVE / AdvisoryCVE-2026-68138
Categorybinary
SeverityHigh
CVSS Score7.8 (estimated, local LPE)
StatusPatched
Tagslinux, 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

FieldValue
Software / SystemLinux kernel, traffic-control qdisc rate-table subsystem (qdisc_get_rtab / qdisc_put_rtab)
Versions AffectedLinux 5.1 through 7.1.5; Linux 7.2-rc1 through 7.2-rc4
Language / PlatformC (exploit), targets x86-64 Linux with unprivileged user namespaces
Authentication RequiredLocal unprivileged user (UID 1000)
Network Access RequiredNone – 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:

Output
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

  1. 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.
  2. 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_FILTER detects when two sockets share the same BPF buffer.
  3. Pipe leak: Closing one owner frees the BPF buffer after RCU. 32-slot pipe rings reclaim it. Reading the other socket via SO_GET_FILTER discloses live pipe_buffer page and ops pointers.
  4. Page-cache overwrite: simple_xattr spray reclaims the freed pipe ring with a forged pipe_buffer with CAN_MERGE set. Writing to candidate pipes appends bytes to the /sbin/modprobe page-cache page.
  5. 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

Shell script
1
2
./build.sh
gcc -O2 -static -pthread -Wall -Wextra -Werror -o build/exploit exploit.c

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 as upstream-README.md. The Ubuntu-specific variant is in ubuntu/.

Step-by-Step Reproduction

  1. Boot a vulnerable kernel in QEMU with 4 vCPUs and nokaslr (for debugging).
  2. Build the exploit: ./build.sh
  3. Copy to guest via 9p share at /exploit/CVE-2026-68138.
  4. Run as unprivileged user: /exploit/CVE-2026-68138
  5. On miss: Reboot the VM before retrying (global qdisc list may be corrupted).

Expected Output

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

Output

Remediation

ActionDetail
PatchUpdate 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.
WorkaroundDisable unprivileged user namespaces (sysctl kernel.unprivileged_userns_clone=0) to prevent the exploit from creating isolated network namespaces for the race.
VerificationCheck 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.