
本仓库包含针对 CVE-2026-68138 的概念验证型本地权限提升漏洞利用程序,该漏洞是 Linux 流量控制速率表代码中的一个竞态条件。在测试的 QEMU 环境中,该 PoC 可将初始用户命名空间中 UID 为 1000 的普通进程提升为 UID 为 0 的 shell。
警告
此代码会故意破坏内核堆状态。请仅在你拥有的一次性隔离虚拟机中使用。竞态失败或过早清理可能导致客户机内核崩溃。请勿在工作站、服务器或第三方系统上运行。
qdisc_get_rtab() 和 qdisc_put_rtab() 管理着一个进程全局的单向链表 qdisc_rtab_list 和一个普通的非原子 int refcnt。历史上,调用者持有 RTNL 互斥锁,从而对该列表和引用计数的访问进行了串行化。
flower 分类器设置了 TCF_PROTO_OPS_DOIT_UNLOCKED。因此,针对 flower 规则的 RTM_NEWTFILTER 请求可以在没有 RTNL 的情况下到达 police 动作并调用 qdisc 速率表辅助函数:
tc_new_tfilter()
-> fl_change()
-> tcf_exts_validate_ex()
-> tcf_action_init()
-> tcf_police_init()
-> qdisc_get_rtab()/qdisc_put_rtab()
使用同一速率表的并发请求可能对该全局列表及其引用计数产生竞态。结果是 struct qdisc_rate_table 的释放后使用或双重释放;在测试的 x86-64 内核上,这是一个从 kmalloc-2k 分配的 1056 字节对象。
由于该列表是全局的而非每网络命名空间一个,因此来自不同网络命名空间的请求仍会对同一对象产生竞态。
Linux CNA 记录将引入提交
470502de5bdb
标识为在 Linux 5.1 中发布。
发行版内核经常在不切换到上述上游版本的情况下向后移植修复补丁。请检查系统实际使用的内核源码中是否存在任一修复提交(或等效的 qdisc 速率表自旋锁改动)。
该漏洞利用程序是针对存在漏洞的提交 92d3817649df2b0b6a008a686c8275c88d7ef594(主线修复的直接父提交)开发和验证的。修复内核的对照组使用了 f43ee0c0730d6191629b5ee1ceae27b1ebfdc047。
截至 2026-08-12,Ubuntu CVE 跟踪器搜索 未返回此 CVE 的条目。因此,下表为直接源码检查结果,而非 Canonical 安全状态判定。每个链接的 Ubuntu 标签仍包含未加锁的 qdisc_rtab_list,且缺少修复用的 qdisc_rtab_lock。
在该检查日期未发现已修正的 Ubuntu 包。应检查未来的 Ubuntu 包是否包含与所链接上游修复等效的向后移植补丁,而不应仅根据其版本号判断。
特定构建的 Ubuntu 22.04 漏洞利用程序、QEMU 实验环境、精确镜像校验和及条件记录在 ubuntu/README.md 中。它已在启用内存 cgroup 记账的官方 5.15.0-187-generic #197-Ubuntu 内核上验证通过。
底层漏洞和这条特定的漏洞利用链有不同的要求。PoC 已验证的条件包括:
CONFIG_USER_NS=y 和 CONFIG_NET_NS=y;CONFIG_NET_CLS=y、CONFIG_NET_CLS_FLOWER=y、
CONFIG_NET_CLS_ACT=y 和 CONFIG_NET_ACT_POLICE=y;CONFIG_TMPFS_XATTR=y,用于 simple_xattr 堆喷射;CONFIG_MODULES=y 和一个可用的 /sbin/modprobe,用于最终的 root 辅助程序;CONFIG_MEMCG=n,使此链使用的 qdisc/BPF/pipe/xattr 分配共享预期的 kmalloc-2k 缓存;在成功测试的内核中启用了 CONFIG_SLAB_BUCKETS=y、空闲链表随机化和空闲链表加固。KASLR 并非通过硬编码地址被固有地绕过:PoC 通过管道泄漏获取所需的页面和操作指针。提供的实验环境使用 nokaslr 来简化调试。
启用了内存 cgroup 记账或具有不同分配器/缓存布局的内核需要不同的回收策略。PoC 刻意不声称可移植到任意的发行版配置。
独立的 Ubuntu 变体实现了这种不同的回收策略;其要求有意收窄,并已列在 ubuntu/README.md 中。
四个工作线程进入不同的网络命名空间并创建带有 police 动作的 flower 过滤器。其中三个工作线程走成功动作路径;一个线程在获取两个速率表引用后故意提供一个无效的估算器,从而强制走清理路径。这种组合可在工作线程之间不共享 flower 分类器状态的情况下复现并发的引用计数和列表操作。
qdisc_rate_table每次 netlink 请求后,同一 CPU 会立即附加一个 133 条指令的经典 BPF 过滤器。其 1064 字节的指令数组从 kmalloc-2k 分配,并在形状上保证与 qdisc_rate_table.next 和 qdisc_rate_table.refcnt 重叠的字节最初保持有效。
最后一条指令包含一个逐套接字标记。SO_GET_FILTER 使 PoC 能够检测某个套接字的 orig_prog->filter 指针何时被重定向到另一个有效的 BPF 分配。这样就产生了两个引用同一指令缓冲区的套接字对象。
关闭其中一个持有者会通过 sk_filter_release_rcu() 推迟实际释放。宽限期结束后,PoC 分配 32 槽的管道环形缓冲区:
32 * sizeof(struct pipe_buffer) = 32 * 40 = 1280 bytes -> kmalloc-2k
其中一个环形缓冲区回收了被别名的 BPF 缓冲区。用 SO_GET_FILTER 读取另一个套接字会泄露一个存活的 pipe_buffer,包括其 page 和 ops 指针以及 /sbin/modprobe 页缓存条目的偏移量。
关闭第二个套接字会在另一个 RCU 宽限期后释放存活的管道环形缓冲区,而对应的 pipe_inode_info 仍引用它。simple_xattr 喷射回收了该 1280 字节的环形缓冲区,并将泄露的 pipe_buffer 放置在预期的槽位,且设置了 PIPE_BUF_FLAG_CAN_MERGE。
向每个候选管道写入最终会将攻击者控制的字节追加到 /sbin/modprobe ELF 入口点所对应的页缓存页。PoC 读回该文件,并在确认精确覆盖后才继续。
近期内核不再使用 search_binary_handler() 中历史上用于无效 binfmt 的模块自动加载回退。此 PoC 改为创建一个使用不受支持的协议 253 的 AF_INET 数据报套接字。inet_create() 请求缺失的 net-pf-2-proto-253-type-2 模块,导致内核以初始命名空间 root 身份执行被覆盖的 /sbin/modprobe。
注入的入口点载荷会写入一个证明文件,并在 QEMU 串行控制台上打开 root shell。
客户机二进制文件为静态链接:
./build.sh
等效命令:
gcc -O2 -static -pthread -Wall -Wextra -Werror \
-o build/exploit exploit.c
生成的二进制文件必须在客户机内部以 /exploit/CVE-2026-68138 路径暴露。测试实验室使用了 QEMU 的读写 9p 共享。root 辅助程序期望该共享位于初始挂载命名空间下的 /chroot/exploit;如果实验室使用其他布局,请调整 exploit.c 中的 helper_command。
相关的测试内核选项记录在 config.fragment 中。它们是一个片段,而不是完整的生产内核配置。
从非特权客户机 shell 中运行:
id
/exploit/CVE-2026-68138
该竞态是概率性的。失败时 PoC 会输出:
[-] no BPF alias found in this attempt
重试前请重启虚拟机。不要在同一客户机中重复运行:全局 qdisc 列表可能已被破坏。
成功执行时会达到以下输出:
[+] 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)
完整的脱敏记录位于 docs/example-output.txt。
完整漏洞利用链已从全新的存在漏洞虚拟机启动环境中成功完成三次。最终二进制文件产生了如下输出:
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)
同一二进制文件在相同的四 vCPU 拓扑下针对修复提交运行。约 126,000 次竞态请求完成,未出现 BPF 别名,也未到达管道或页缓存阶段。
Ubuntu 专用变体也针对精确的官方 5.15.0-187.197 通用内核运行。客户机以四个 vCPU、正常的内存 cgroup 记账启动,nokaslr 是唯一的漏洞利用专用内核参数。
Ubuntu 内核未被重新编译:测试使用了发行版未修改的 vmlinuz-5.15.0-187-generic 和匹配的官方模块。Ubuntu 先决条件表 将原装内核特性与运行时及 QEMU 实验环境调整区分开来。
起始账户没有 sudo 权限或补充组:
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu)
从新快照开始,该漏洞利用程序获取了 BPF 别名,通过 cgroup-v2 simple_xattr 对象和阻塞式 select() 位图回收了它,验证了 /proc/sys/kernel/modprobe 包含 /tmp/x,并达到:
[+] 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)
请参阅 真实 QEMU 记录 和 Ubuntu 实验环境说明。该变体为此包硬编码了 modprobe_path 地址,因此需要 nokaslr;它并不声称绕过 KASLR 或与其他 Ubuntu 构建兼容。
该补丁已是 Linux 内核的一部分,因此本仓库中不再重复提供。权威的稳定版和主线修复提交见下方引用。
研究与漏洞利用实现:A. Ramos <[email protected]>
(Twitter:@aramosf)。
| 版本线 | 状态 | 提交/版本 |
|---|
| Linux 5.1 之前 | 不受影响 | 不包含引入该漏洞的改动 |
| Linux 5.1 至 7.1.5 | 受影响(除非存在厂商向后移植补丁) | 从 470502de5bdb 到稳定修复之前的提交 |
| Linux 7.1.y | 已修复 | 7.1.6,fb29e1b41052 |
| Linux 7.2 开发系列 | rc5 之前受影响 | rc1 至 rc4 |
| 主线 | 已修复 | 7.2-rc5,f43ee0c0730d |
| Ubuntu 版本线 | 已检查的包/标签 | 源码检查结果 |
|---|
| Ubuntu 22.04 GA | 5.15.0-187.197 | 存在漏洞代码;已在 QEMU 中完整复现漏洞利用 |
| Ubuntu 22.04 HWE | 6.8.0-136.136~22.04.1 | 存在漏洞代码;漏洞利用链未经测试 |
| Ubuntu 24.04 HWE | 7.0.0-28.28~24.04.1 | 存在漏洞代码;此漏洞利用链与其分配器加固不兼容 |
| Ubuntu 26.04 | 7.0.0-28.28 | 存在漏洞代码;此漏洞利用链与其分配器加固不兼容 |