Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-68138 — Proof-of-concept local privilege escalation exploit for a Linux qdisc rate-table race condition, using BPF heap grooming and a pipe leak to gain root. | Kitploit
Tools/GitHubGitHub/aramosf/cve-2026-68138
Privilege EscalationVulnerability AnalysisExploitationBinary Exploitation
GitHubaramosf/cve-2026-68138

CVE-2026-68138

Proof-of-concept local privilege escalation exploit for a Linux qdisc rate-table race condition, using BPF heap grooming and a pipe leak to gain root.

View Repository
336428 days agoReviewed by Kitploit

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-68138: Linux qdisc rate-table race to local root

CVE-2026-68138 live exploit

This repository contains a proof-of-concept local privilege-escalation exploit for CVE-2026-68138, a race in the Linux traffic-control rate-table code. In the tested QEMU environment, the PoC escalates from an ordinary process with outer UID 1000 to a shell with UID 0 in the initial user namespace.

Warning

This code intentionally corrupts kernel heap state. Use it only in an isolated, disposable VM that you own. A missed race or premature cleanup can panic the guest. Do not run it on a workstation, server, or third-party system.

Vulnerability summary

qdisc_get_rtab() and qdisc_put_rtab() manage a process-global singly linked list, qdisc_rtab_list, and a plain non-atomic int refcnt. Historically, callers held the RTNL mutex, which serialized access to the list and reference count.

The flower classifier sets TCF_PROTO_OPS_DOIT_UNLOCKED. An RTM_NEWTFILTER request for a flower rule can consequently reach a police action and call the qdisc rate-table helpers without RTNL:

root@kitploit:~
tc_new_tfilter()
  -> fl_change()
     -> tcf_exts_validate_ex()
        -> tcf_action_init()
           -> tcf_police_init()
              -> qdisc_get_rtab()/qdisc_put_rtab()

Concurrent requests using the same rate table can race the global list and its reference count. The result is a use-after-free or double-free of struct qdisc_rate_table, a 1056-byte object allocated from kmalloc-2k on the tested x86-64 kernel.

Because the list is global rather than per-network-namespace, requests from separate network namespaces still race the same object.

Affected and fixed versions

The Linux CNA record identifies introduction commit 470502de5bdb, released in Linux 5.1.

Distribution kernels frequently backport fixes without changing to the upstream version shown above. Check whether either fixing commit—or the equivalent qdisc rate-table spinlock change—is present in the exact kernel source used by the system.

The exploit was developed and validated against vulnerable commit 92d3817649df2b0b6a008a686c8275c88d7ef594, the direct parent of the mainline fix. The fixed-kernel control used f43ee0c0730d6191629b5ee1ceae27b1ebfdc047.

Ubuntu distribution status

As of 2026-08-12, the Ubuntu CVE tracker search did not return an entry for this CVE. The table below is therefore a direct source inspection, not a Canonical security-status determination. Each linked Ubuntu tag still has the unlocked qdisc_rtab_list and lacks the fixing qdisc_rtab_lock.

No corrected Ubuntu package was identified at that inspection date. Future Ubuntu packages should be checked for a backport equivalent to the linked upstream fixes rather than judged only by their version number.

The build-specific Ubuntu 22.04 exploit, QEMU lab, exact image checksum, and conditions are documented in ubuntu/README.md. It was validated against the official 5.15.0-187-generic #197-Ubuntu kernel with memory-cgroup accounting enabled.

Conditions required by the main PoC

The underlying bug and this particular exploit chain have different requirements. The PoC was validated with:

  • x86-64 Linux and four virtual CPUs;
  • unprivileged user namespaces and network namespaces enabled;
  • CONFIG_USER_NS=y and CONFIG_NET_NS=y;
  • CONFIG_NET_CLS=y, CONFIG_NET_CLS_FLOWER=y, CONFIG_NET_CLS_ACT=y, and CONFIG_NET_ACT_POLICE=y;
  • classic BPF socket filters and BPF JIT support;
  • CONFIG_TMPFS_XATTR=y for the simple_xattr heap spray;
  • CONFIG_MODULES=y and a usable /sbin/modprobe for the final root helper;
  • CONFIG_MEMCG=n, so the qdisc/BPF/pipe/xattr allocations used by this chain share the expected kmalloc-2k cache;
  • a per-process file-descriptor limit of at least 4096; and

CONFIG_SLAB_BUCKETS=y, freelist randomization, and freelist hardening were enabled in the successful test kernel. KASLR is not inherently bypassed with a hard-coded address: the PoC obtains the required page and operations pointers from the pipe leak. The supplied lab used nokaslr to simplify debugging.

Kernels with memory-cgroup accounting enabled or different allocator/cache layouts require a different reclaim strategy. The PoC deliberately refuses to claim portability across arbitrary distribution configurations.

The separate Ubuntu variant implements that different reclaim strategy; its requirements are intentionally narrower and are listed in ubuntu/README.md.

Exploitation process

1. Trigger the qdisc race

Four worker threads enter distinct network namespaces and create flower filters with police actions. Three workers take the successful action path; one supplies a deliberately invalid estimator after acquiring both rate-table references, forcing the cleanup path. This combination makes concurrent reference-count and list manipulation reproducible without sharing flower classifier state between workers.

2. Reclaim qdisc_rate_table with classic BPF

After every netlink request, the same CPU immediately attaches a 133-instruction classic-BPF filter. Its 1064-byte instruction array is allocated from kmalloc-2k and is shaped so the bytes overlapping qdisc_rate_table.next and qdisc_rate_table.refcnt initially remain valid.

The final instruction contains a per-socket marker. SO_GET_FILTER lets the PoC detect when one socket's orig_prog->filter pointer has been redirected to another live BPF allocation. This yields two socket objects referring to the same instruction buffer.

3. Convert the alias into a pipe leak

Closing one owner defers the actual free through sk_filter_release_rcu(). After the grace period, the PoC allocates 32-slot pipe rings:

root@kitploit:~
32 * sizeof(struct pipe_buffer) = 32 * 40 = 1280 bytes -> kmalloc-2k

One ring reclaims the aliased BPF buffer. Reading the other socket with SO_GET_FILTER discloses a live pipe_buffer, including its page and ops pointers and the offset of the /sbin/modprobe page-cache entry.

4. Forge a mergeable pipe buffer

Closing the second socket frees the live pipe ring after another RCU grace period, while the corresponding pipe_inode_info still references it. A simple_xattr spray reclaims the 1280-byte ring and places the leaked pipe_buffer at the expected slot with PIPE_BUF_FLAG_CAN_MERGE set.

Writing to each candidate pipe eventually appends attacker-controlled bytes to the page-cache page backing the ELF entry point of /sbin/modprobe. The PoC reads the file back and proceeds only after confirming the exact overwrite.

5. Execute in the initial namespace

Recent kernels no longer use the historical invalid-binfmt module-autoload fallback in search_binary_handler(). This PoC instead creates an AF_INET datagram socket with unsupported protocol 253. inet_create() requests the missing net-pf-2-proto-253-type-2 module, causing the kernel to execute the overwritten /sbin/modprobe as initial-namespace root.

The injected entry-point payload writes a proof file and opens a root shell on the QEMU serial console.

Building the PoC

The guest binary is statically linked:

root@kitploit:~
./build.sh

Equivalent command:

root@kitploit:~
gcc -O2 -static -pthread -Wall -Wextra -Werror \
  -o build/exploit exploit.c

The resulting binary must be exposed inside the guest as /exploit/CVE-2026-68138. The tested lab used QEMU's read-write 9p share. The root helper expects that share at /chroot/exploit from the initial mount namespace; adjust helper_command in exploit.c if the lab uses another layout.

The relevant test-kernel options are recorded in config.fragment. They are a fragment, not a complete production kernel configuration.

Running

From the unprivileged guest shell:

root@kitploit:~
id
/exploit/CVE-2026-68138

The race is probabilistic. On a miss the PoC prints:

root@kitploit:~
[-] no BPF alias found in this attempt

Reboot the VM before retrying. Do not rerun it in the same guest: the global qdisc list may already have been corrupted.

A successful execution reaches:

root@kitploit:~
[+] 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)

The complete sanitized transcript is in docs/example-output.txt.

Reproduced results

The full chain was completed three times from fresh vulnerable VM boots. The final binary produced:

root@kitploit:~
outer identity: uid=1000(user)
alias:          classic-BPF orig_prog->filter overlap
leak:           live pipe_buffer page and ops pointers
write:          verified /sbin/modprobe page-cache modification
final identity: uid=0(root) gid=0(root) groups=0(root)

The same binary was run against the fixed commit with the same four-vCPU topology. Approximately 126,000 race requests completed without a BPF alias, and no pipe or page-cache stage was reached.

Ubuntu 22.04.5 QEMU result

The Ubuntu-specific variant was also run against the exact official 5.15.0-187.197 generic kernel. The guest booted with four vCPUs, normal memory-cgroup accounting, and nokaslr as the only exploit-specific kernel argument.

The Ubuntu kernel was not recompiled: the test used the distribution's unchanged vmlinuz-5.15.0-187-generic and matching official modules. The Ubuntu prerequisite table separates stock kernel features from runtime and QEMU lab adjustments.

The starting account had no sudo access or supplementary groups:

root@kitploit:~
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu)

From a fresh snapshot, the exploit obtained the BPF alias, reclaimed it through cgroup-v2 simple_xattr objects and blocking select() bitmaps, verified that /proc/sys/kernel/modprobe contained /tmp/x, and reached:

root@kitploit:~
[+] CVE-2026-68138 Ubuntu initial-namespace root shell
uid=0(root) gid=0(root) groups=0(root)
root@cve-2026-68138-jammy:/# id
uid=0(root) gid=0(root) groups=0(root)

See the real QEMU transcript and the Ubuntu lab instructions. The variant hard-codes the modprobe_path address for this package and therefore requires nokaslr; it does not claim a KASLR bypass or compatibility with another Ubuntu build.

Fix

The patch is already part of the Linux kernel and is therefore not duplicated in this repository. The canonical stable and mainline fixing commits are linked in the references below.

References

  • Official CVE record
  • Stable fix for Linux 7.1.y
  • Mainline fix
  • Ubuntu CVE tracker search
  • Official Ubuntu Jammy cloud image

Research and exploit implementation: A. Ramos <[email protected]> (Twitter: @aramosf).

Download Tool
LineStatusCommit/version
Linux before 5.1Not affectedThe introducing change is absent
Linux 5.1 through 7.1.5Affected unless a vendor backport is present470502de5bdb through the commit before the stable fix
Linux 7.1.yFixed7.1.6, fb29e1b41052
Linux 7.2 development seriesAffected before rc5rc1 through rc4
MainlineFixed7.2-rc5, f43ee0c0730d
Ubuntu lineInspected package/tagSource result
Ubuntu 22.04 GA5.15.0-187.197Vulnerable code present; full exploit reproduced in QEMU
Ubuntu 22.04 HWE6.8.0-136.136~22.04.1Vulnerable code present; exploit chain not tested
Ubuntu 24.04 HWE7.0.0-28.28~24.04.1Vulnerable code present; this exploit chain is not compatible with its allocator hardening
Ubuntu 26.047.0.0-28.28Vulnerable code present; this exploit chain is not compatible with its allocator hardening
  • a disposable VM with approximately 5 GiB of RAM.