Featured image of post pedit COW:一场在页面缓存里悄无声息的 root 政变

pedit COW:一场在页面缓存里悄无声息的 root 政变

CVE-2026-46331 深度分析:act_pedit 越界写入如何绕过 CoW,投毒 /bin/su 页面缓存实现本地提权。附完整攻防推演、检测方案与加固实操。

真正的剑客不在杯中寻毒,而在茶里看见破绽。内核亦然。

零、一句话概括

CVE-2026-46331(绰号 “pedit COW”)是 Linux 内核流量控制子系统中的一个越界写入漏洞。攻击者利用 act_pedit 模块在 Copy-on-Write 阶段的校验缺陷,对共享页面缓存进行越界写入,在不触碰磁盘文件的情况下毒化 /bin/su 的内存映射,最终以非特权用户身份获取 root 权限。

CVSS 评分:7.8(HIGH)|攻击复杂度:低|利用条件:本地、非特权用户在启用了非特权用户命名空间的系统上

漏洞曝出不到 24 小时,公开 PoC 即现身 GitHub。这是一场从 mailing list 上被低估的「例行数据损坏补丁」到 weaponized exploit 的经典演变。


一、先复盘:CoW 这一类漏洞的血脉传承

如果你对 Linux 内核的 page-cache 漏洞稍有涉猎,应该已经对这个家族不陌生了:

漏洞名称CVE年份核心手法
Dirty PipeCVE-2022-08472022splice() 未重置 pipe buffer flags,向已释放的 page cache 写入
Copy FailCVE-2024-XXXX2024copy_file_range() 的 CoW 断裂
DirtyCloneCVE-2026-XXXX2026io_uring 零拷贝路径越过 page 所有权检查
Dirty FragCVE-2026-XXXX2026碎片整理过程中 page 引用计数竞争
pedit COWCVE-2026-463312026act_pedit 运行时偏移解析绕过越界检查

它们的本质是同一个「脉门」:

内核在某条快速路径上对页面做了写操作,但这个页面并不归它独占。

这不是内存破坏(memory corruption),这是逻辑漏洞。不涉及 ROP、不涉及 KASLR 绕过、不涉及堆喷。只需要知道哪一页被共享,然后把 payload 写进去——文件完整性校验会告诉你一切正常,而你早已是 root。


二、漏洞机制:一封被投毒的信,信封完好无损

2.1 act_pedit 的正常工作流

tc(traffic control)是 Linux 的流量整形瑞士军刀。其中 pedit action 可以在数据包经过时,实时修改包头字段——比如改 TTL、改 DSCP、改 IP 地址。

当你配置一条 pedit 规则并触发它时,内核调用链大致是:

tcf_pedit_act()
  → pedit_skb_hdr_offset()    // 计算偏移
  → tcf_pedit_act() 内部       // 校验写入范围
  → 如果页面是共享的(refcount > 1)
      → 创建私有副本 (CoW)
  → 写入数据

理想情况下,CoW 保护在写入前完成,shared page 永远不被污染。

2.2 断裂点在哪里?

问题出在两次偏移解析之间

第一次校验发生在 tcf_pedit_act() 计算 nkeys 时,它检查所有 key 的 offsetvalmask 组合后的总写入范围是否合法。此时对于某些特殊的 key 类型(偏移在运行时依赖实际数据包头内容才能确定),内核使用的是一种「预留槽」机制——先分配了一个最大范围,但没有精确锁定每个 key 的最终落点。

第二次,也就是实际写入时,这些 key 的偏移被运行时解析(例如基于 VLAN tag 层数动态计算)。如果运行时解析出的偏移超出了第一次校验时预留的私有副本范围——

写入操作就越界落回了共享的 page cache 页

用一句话讲:

它量好尺寸才去借西装,结果扣子缝歪了,扎到了别人的皮肤上。

2.3 投毒链条

攻击者的完整攻击链:

1. 创建用户命名空间 → 获得 namespace-local CAP_NET_ADMIN
2. 加载 act_pedit 模块(如果未加载)
3. 打开 /bin/su(setuid root)→ 页面进入 page cache(共享状态)
4. 构造 tc pedit 规则,精确计算偏移使写入落在 /bin/su 的内存页中
5. 触发规则,向 cached page 注入 shellcode / 修改逻辑
6. 执行被投毒的 /bin/su → 内核看到 setuid bit + 文件未修改(磁盘是干净的)
   → 实际执行的是被污染的内存页中的代码
   → 获得 root shell

精妙之处:它不需要写 /etc/passwd、不需要改 sudoers、不触发任何文件系统级别的审计日志。整个攻击在内存中完成,文件哈希不变,AIDE/Tripwire 静默。


三、为什么这次特别危险?

3.1 入口门槛低

过去的 page-cache 漏洞往往需要特定条件:

  • Dirty Pipe 需要 pipe + splice 的配合
  • DirtyClone 需要 io_uring 支持

而 pedit COW 的入口是 非特权用户命名空间 + 可加载的内核模块。在主流发行版的默认配置下,这两项都是开启的:

发行版unprivileged usernsact_pedit 可用默认可被利用?
RHEL 8/9/10✅ 默认开启✅ 内核内置或可加载
Debian 11/12/13 (trixie)✅ 默认开启✅ 可加载
Ubuntu 18.04-24.04✅ 默认开启✅ 可加载✅(24.04 需绕 AppArmor)
Ubuntu 26.04✅ 内核支持✅ 可加载⚠️ AppArmor 默认阻断 userns

3.2 检测盲区

传统检测手段几乎全部失效:

  • 文件完整性监控(AIDE/Samhain/Tripwire):磁盘文件未被修改 → 通过
  • auditd 文件访问日志:只监控 syscall 层面的 open/read/write → 不覆盖 page cache 操作
  • 杀毒软件:无法扫描内核态的内存写入
  • EDR/HIDS:除非 hook 了内核函数,否则看不到 tcf_pedit_act 内部的越界写入

唯一有效的检测是行为审计:一个非特权用户突然执行了 tc 命令并带着 pedit action,这本身就是异常信号。但攻击者可以在投毒后清理 tc 规则,痕迹只留在一瞬间。

3.3 时间线令人不安

2026-05-23  补丁出现在 netdev mailing list(标注为"数据损坏修复")
2026-06-16  CVE 编号分配(补丁合入主线)
2026-06-17  公开 PoC 发布
2026-06-26  The Hacker News 报道
2026-06-29  本文发布时,大量发行版仍未推送修复

3 周——从补丁公开到武器化利用。如果一个漏洞的补丁在 mailing list 上躺了三周而无人重视,那它不是被遗忘,而是被忽视了。


四、攻防实操

4.1 复现环境(PoC 已验证)

根据公开 PoC 的测试结果:

  • RHEL 10:直接提权成功,无任何阻断
  • Debian 13 (trixie):直接提权成功
  • Ubuntu 24.04:需通过 AppArmor profile 路由(利用仍可用的 profiles),提权成功
  • Ubuntu 26.04:AppArmor 阻断默认 user namespace 创建,exploit 在此环境下失败(但内核本身仍然脆弱)

PoC 地址:github.com/sgkdev/packet_edit_meme

4.2 快速自查

# 1. 检查内核版本
uname -r

# 2. 检查 act_pedit 模块是否可加载(存在 .ko 文件即危险)
find /lib/modules/$(uname -r) -name '*act_pedit*'

# 3. 检查 unprivileged user namespaces 状态
# Debian/Ubuntu:
cat /proc/sys/kernel/unprivileged_userns_clone
# RHEL/CentOS:
cat /proc/sys/user/max_user_namespaces

# 4. 综合判定:
#    - 内核版本 < 修复版本(各发行版自行查询)
#    - act_pedit 模块可用(.ko 存在或已加载)
#    - unprivileged userns = 1(或 max_user_namespaces > 0)
#    → 系统存在被利用条件

4.3 立即处置:两条防线,双管齐下

防线一:阻断 act_pedit 模块加载

# 检查模块是否已加载
lsmod | grep act_pedit

# 永 久阻止加载
echo 'install act_pedit /bin/true' | sudo tee /etc/modprobe.d/disable-act_pedit.conf

# 如果已加载,立即卸载
sudo rmmod act_pedit 2>/dev/null

此项操作不影响正常网络功能——除非你主动使用 tc pedit 修改数据包头。绝大多数服务器不需要此功能。

防线二:禁用非特权用户命名空间

# Debian/Ubuntu(立即生效 + 持久化)
sudo sysctl -w kernel.unprivileged_userns_clone=0
echo "kernel.unprivileged_userns_clone = 0" | sudo tee /etc/sysctl.d/99-disable-userns.conf

# RHEL/CentOS
sudo sysctl -w user.max_user_namespaces=0
echo "user.max_user_namespaces = 0" | sudo tee /etc/sysctl.d/99-disable-userns.conf

⚠️ 警告:禁用 unprivileged userns 会破坏 rootless 容器(Podman rootless、Docker rootless)、部分 CI 沙箱、以及基于命名空间隔离的浏览器沙箱(Chromium/Firefox)。在生产环境操作前务必评估影响。

防线三:升级内核并重启

这是唯一彻底的修复方案。对于无法立即重启的系统,前两条防线是救命稻草。

# Ubuntu/Debian
sudo apt update && sudo apt install linux-image-generic -y
sudo reboot

# RHEL/CentOS
sudo yum update kernel -y
sudo reboot

4.4 事故后的取证思路

如果怀疑已被入侵:

# 1. 检查 tc 规则中是否有异常的 pedit action
tc -s filter show dev lo 2>/dev/null
tc -s filter show dev eth0 2>/dev/null

# 2. 清除页面缓存(会丢掉攻击痕迹,但至少确保当前运行的二进制是干净的)
echo 3 | sudo tee /proc/sys/vm/drop_caches

# 3. 检查是否有异常 root shell 进程(如 /bin/su 的不正常子进程)
ps auxf | grep -v grep | grep -E 'su|bash.*root'

# 4. 全面取证:dump 内存、检查 auditd 日志时间线上的 tc 命令
#    但因攻击在内存中完成,磁盘取证价值有限。
#    原则:发现被利用 → 视为完全失陷 → 重装系统,不是清理。

五、写在最后:从补丁到武器,中间到底差了什么?

这个漏洞最让人脊背发凉的,不是它的技术复杂度(实际上比 Dirty Pipe 更简单),而是信息差

5 月 23 日,补丁出现在 netdev mailing list,标题平淡无奇,归类为「数据损坏修复」。没有人标注 Security、没有人分配 CVE、没有人拉响警报。

6 月 16 日,补丁合入主线,CVE 下发。

6 月 17 日,exploit 发布。

从 mailing list 到 weaponized PoC,跨度三周。而直到 6 月底,大量生产系统依然暴露。

这不是 0day,这是 -21day——防御方有 21 天的时间窗口,但没有人认出这是一道裂缝。

安全社区需要反思的不只是代码质量,更是对补丁中「无关紧要的修复」的嗅觉。

内核 page-cache 写入路径上的任何校验变更——哪怕是「修复数据损坏」——都应该自动触发安全团队的审视。因为在这个领域,数据损坏和权限提升之间的距离,往往只隔着一个 setuid 位。


六、资源链接


逍遥微信二维码

联系逍遥

扫码添加微信,或点击下方按钮复制联系方式。

进微信群请联系博主,各位觉得文章对你有帮助的话可否打赏一些呀~


站长推荐
Hello World | 开启技术博客之旅
从这里开始阅读本站的网络安全、AI 与技术实践内容。
查看文章 →
订阅更新
通过 RSS 阅读本站
不依赖平台算法,第一时间获取新文章。
订阅 RSS →
站长推荐
Hello World | 开启技术博客之旅
从这里开始阅读本站的网络安全、AI 与技术实践内容。
查看文章 →
订阅更新
通过 RSS 阅读本站
不依赖平台算法,第一时间获取新文章。
订阅 RSS →