在运行时使用 Cilium Tetragon TracingPolicy 阻止 DirtyFrag Linux 权限提升利用链(CVE-2026-43284 / CVE-2026-43500)。该策略在其套接字设置步骤将公开的概念验证程序 SIGKILL,使其无法到达会赋予 root 权限的页缓存写入操作。
这是什么。 一份实验报告。我第一次搭建 Tetragon,想看看它是否真的能阻止一个真实的、当前内核的权限提升漏洞。它做到了。本文档精确记录了我运行了什么、触发了什么,以及同样重要的是,它所证明的局限。这不能替代打补丁。
文件:本 README(自包含,内嵌证据)· block-dirtyfrag.yaml(策略)
| 漏洞利用 | DirtyFrag - 公开 PoC:V4bel/dirtyfrag |
| CVE | CVE-2026-43284(xfrm-ESP 页缓存写入),CVE-2026-43500(RxRPC 页缓存写入) |
| 主机 | Ubuntu 24.04.4 LTS,Tetragon v1.7.0(独立运行,systemd) |
基准测试 - 无策略,内核 6.8.0-88(存在漏洞) | PoC → uid=0(root) |
启用策略 - 内核 6.8.0-88 | PoC 在 socket(AF_RXRPC) 处被 SIGKILL;用户保持 uid=1000 |
已修补内核 6.8.0-134 | PoC 自行失败(rc=4);套接字钩子仍会触发,属于检测,而非缓解(注意) |
| 控制性质 | 补偿性控制/虚拟补丁,并非内核修复 |
DirtyFrag 是一个本地提权利用链,由 Linux 内核中两个独立的页缓存写入原语构成:一个在 xfrm/ESP(IPsec)原地解密路径(CVE-2026-43284),另一个在 RxRPC 路径(CVE-2026-43500)。每个原语都允许非特权本地用户将攻击者控制的字节写入只读的页缓存页面,例如 setuid-root 二进制文件(如 /bin/su)的缓存映像——并由此获得 root 权限。写入操作仅发生在内存中;磁盘上的文件从未被修改,因此文件完整性监控不会发现任何异常。它与 Dirty Pipe 和 Copy Fail 属于同一漏洞类型。这两个 CVE 被刻意链接在一起:如果在特定环境中一条路径不可用,另一条仍然有效。
在此主机上,非特权用户命名空间被 AppArmor 限制(kernel.apparmor_restrict_unprivileged_userns = 1),这阻止了利用链的 ESP 部分。剩下的就是 RxRPC 路径,它打开一个 AF_RXRPC 套接字(地址族 33)——正是这一步被本策略杀死。
真正的修复是修补内核。 这里的一切都是针对尚无法修补的主机的临时措施。Ubuntu 在此测试前一段时间已发布 DirtyFrag 修复,因此这是一个已知的 N-day,而非实时 0-day——重点是展示运行时控制在一个因各种原因仍在运行有漏洞内核的主机上能起到什么作用。
完整策略:block-dirtyfrag.yaml。它安装了两个 kprobe。
钩子 1 - 准备套接字(sys_socket)。 承担主要负载的控制点。漏洞利用的 RxRPC 路径必须在每次运行时调用 socket(AF_RXRPC, …),无论任何内核模块是否已加载。策略匹配地址族:
AF_RXRPC)→ Sigkill。 在非 AFS 客户端的主机上,几乎没有任何合法操作会打开 AF_RXRPC 套接字,因此此处全部杀死是安全且高置信度的。AF_ALG)→ Post(仅审计,不杀死)。 AF_ALG 是用户空间的内核加密 API,确实有合法用户(cryptsetup、libkcapi 工具、某些 FIPS 工作流)。仅按族杀死会导致误报,因此此分支仅记录日志。执行路径是:先审计一段时间,根据实际观察到的二进制文件构建一个 NotIn 白名单,然后考虑升级为 Sigkill。钩子 2 - 脆弱模块自动加载(security_kernel_module_request)。 纵深防御。当内核被请求自动加载一个存在漏洞的模块族(esp4、esp6、rxrpc、net-pf-33/net-pf-38 套接字别名、pcbc/fcrypt 加密模板)时触发。限制: 仅当模块尚未驻留时才会触发——在启动后第一次运行漏洞利用后,这些模块已加载,此钩子将静默。它是一个冷启动层,而非主要控制点。
结合起来:钩子 1 在模块热或冷时都能捕获漏洞利用;钩子 2 在冷主机上提供了更早、更具体的触发点。
6.8.0-88-generic 上取得的(基准测试可达到 root)。这台机器也安装了 6.8.0-134-generic——已修补的内核——并且已直接确认:重新启动进入 -134 会导致 PoC 自行失败(rc=4,无 root),无论是否有策略(见下面的注意)。要重现缓解演示,请从 GRUB 启动 6.8.0-88(它仍然安装着)——在任何已修补的内核上,没有任何需要缓解的东西。AF_ALG 分支。lockdown,capability,landlock,yama,apparmor——没有 bpf)。因此,强制执行使用来自 kprobe 的 Sigkill,而非内核内 LSM 拒绝。杀死操作发生在 socket() 系统调用处——在写入原语之前——因此它在强制性的早期步骤终止进程,而非“阻止漏洞本身”。步骤 1–5 均来自同一个 6.8.0-88 启动(有漏洞的内核)。
1. 环境 - Ubuntu 24.04.4,内核 6.8.0-88-generic,Tetragon v1.7.0 在 systemd 下运行,非特权用户命名空间受限。
$ uname -r
6.8.0-88-generic
$ tetra version
CLI 版本: v1.7.0
$ systemctl is-active tetragon
active
2. 前提条件(策略关闭) - 干净起始点:不存在有漏洞的模块,无 xfrm 状态,无策略加载。
$ lsmod | grep -E 'esp4|esp6|rxrpc' || echo "(未加载)"
(未加载)
$ sudo ip xfrm state # (空)
$ sudo tetra tp list
ID NAME STATE FILTERID NAMESPACE SENSORS KERNELMEMORY MODE NPOST NENFORCE NMONITOR
3. 基准测试(策略关闭)- 漏洞利用生效。 这证明了内核确实存在漏洞;整个报告都基于此。
$ ./exp ; id
uid=0(root) gid=0(root) groups=0(root)
4. 加载策略。
$ sudo tetra tp add /etc/tetragon/tetragon.tp.d/block-dirtyfrag.yaml
跟踪策略 ".../block-dirtyfrag.yaml" 已添加
5. 强制执行(策略开启)- 杀死操作。 漏洞利用在 socket() 调用处被信号终止,从未到达 su:
🚀 进程 /home/.../dirtyfrag/exp
❓ 系统调用 /home/.../dirtyfrag/exp __x64_sys_socket
内核:
0x0: __x64_sys_socket+0x5
0x0: do_syscall_64+0x7f
0x0: entry_SYSCALL_64_after_hwframe+0x78
💥 退出 /home/.../dirtyfrag/exp SIGKILL
结构化事件同时确认了匹配和杀死——首先是套接字系统调用上的 process_kprobe,然后是同一 PID 由信号触发的 process_exit:
// process_kprobe — AF_RXRPC 匹配
{ "process_kprobe": {
"process": { "pid": 24083, "uid": 1000, "binary": ".../dirtyfrag/exp" },
"function_name": "__x64_sys_socket",
"args": [ { "int_arg": 33, "label": "family" } ],
"policy_name": "block-dirtyfrag",
"action": "KPROBE_ACTION_POST"
} }
// process_exit — 同一 PID,被信号杀死
{ "process_exit": {
"process": { "pid": 24083, "binary": ".../dirtyfrag/exp" },
"signal": "SIGKILL"
} }
kprobe 的 action 显示为 KPROBE_ACTION_POST,因为 Post 操作会发出可见事件;而 Sigkill 操作会产生单独的 SIGKILL 退出。这两个事件共同构成了证据:匹配和杀死。
注意:原始
07捕获内容还带有一个来自早期策略版本(在AF_ALG分支被拆分为仅审计之前)的message字符串。family: 33匹配和由此产生的SIGKILL在不同版本中相同;只有那段文本不同。
在有漏洞内核运行之后,主机被重新启动到 6.8.0-134-generic(Ubuntu 的已修补内核),并再次运行 PoC:
$ ./exp # 策略关闭
dirtyfrag: failed (rc=4) # 漏洞利用自行失败 — 无 root
$ ./exp # 策略开启
Killed # 在 socket(AF_RXRPC) 处 SIGKILL
准确说明这显示了什么:
rc=4,无 root),因为内核已修补。策略没有什么可阻止的。体现缓解主张的前后对比只存在于有漏洞的 -88 内核上。socket(AF_RXRPC),因此 Tetragon 仍然 SIGKILL 它,并在日志中记录该尝试——在已修补的内核上如同在未修补的内核上一样。这作为对尝试的检测和纵深防御是有价值的,但这与阻止一个有效的漏洞利用不同。AF_RXRPC 是合法的,全部杀死会破坏其功能。请按节点验证。AF_ALG 分支默认仅审计。 使用仅 AF_ALG 路径且模块已热的变种会被记录,但不会被杀死——直到您将该分支升级为强制执行(在白名单之后)。AF_RXRPC 套接字在写入原语之前被打开。这种顺序使得早期杀死有效;但这并不能保证适用于每一个可能的漏洞利用。设置:Tetragon v1.7.0 独立运行,通过 systemctl 启动;策略通过 tetra tracingpolicy add 加载。