2026 年 5 月,Linux 内核社区披露了一起影响深远的本地权限提升漏洞。该漏洞存在于 io_uring 子系统的 ZCRX(Zero-Copy Receive)模块中,由于 freelist(空闲链表)管理机制存在竞态条件,可导致释放后重用(Use-After-Free)和越界写入(Out-of-Bounds Write)两类内存破坏问题。在特定条件下,攻击者能够利用该漏洞从普通用户权限提升至 root 权限。目前上游已在 Linux 6.15-6.19 版本中推送修复补丁(commit 770594e),但尚未完全合并至各发行版稳定内核。本文将从技术原理、漏洞机制、利用路径和实际防护措施四个维度,为安全工程师提供可落地的分析与应对指南。
一、ZCRX 架构与 Freelist 内存管理机制
io_uring 是 Linux 内核在 5.1 版本引入的高性能异步 I/O 框架,旨在为应用程序提供低延迟、高吞吐的 I/O 操作接口。ZCRX(Zero-Copy Receive)是 io_uring 中用于网络数据接收的零拷贝扩展模块,允许内核直接将网络数据写入用户空间缓冲区,避免传统 recv () 系统调用中从内核缓冲区到用户缓冲区的数据拷贝过程。这一特性在高性能网络场景(如 DPDK 类应用、高频交易系统)中具有显著价值。
ZCRX 的核心工作流程涉及缓冲区生命周期的精细管理。当用户空间通过 io_uring 注册一块内存区域用于接收数据时,内核会将该区域划分为固定大小的缓冲区块,并使用一个 freelist(空闲链表)来追踪当前可用的缓冲区。典型的 ZCRX 缓冲区管理包括以下关键操作:分配(allocate)时从 freelist 取出一个空闲缓冲区;释放(return)时将缓冲区重新放回 freelist;在某些清理场景下还会执行 scrub(清空)操作以重置缓冲区状态。
问题恰好出在释放(return)操作的实现层面。根据安全研究人员的分析,ZCRX 模块中的缓冲区释放函数 io_zcrx_return_niov_freelist () 存在非原子性的读 - 检查 - 递减序列。具体而言,当多个线程同时处理同一缓冲区的 scrub 和 refill 操作时,可能出现以下竞态条件:线程 A 和线程 B 同时读取到缓冲区的引用计数为 1(即只有一个持有者),双方均认为可以安全地将该缓冲区释放并放回 freelist,随后各自执行递减操作并将同一缓冲区重复添加到 freelist 中。这种双重释放(Double-Free)会导致 freelist 中的空闲缓冲区计数超过实际分配的缓冲区数量,为后续的内存破坏奠定基础。
二、从竞态条件到权限提升的攻击链路
理解 ZCRX freelist 漏洞的利用价值,需要明确其完整攻击链路。该漏洞的严重性不仅在于内存破坏本身,更在于它为本地权限提升提供了可行的攻击路径。
第一阶段是触发双重释放。攻击者需要构造特定的 io_uring 操作序列,使两个线程同时对同一 ZCRX 缓冲区执行释放操作。根据公开的技术分析,触发条件涉及并发提交多个 io_uring 请求,并通过特定的内存压力或调度手段制造线程交错。成功执行后,同一缓冲区会被两次标记为 “空闲” 并添加到 freelist,此时 freelist 的内部状态会呈现不一致性。
第二阶段是实现释放后重用(Use-After-Free)。由于 freelist 中存在重复的缓冲区项,后续的正常缓冲区分配操作可能将已经被释放的内存重新分配给另一个请求。此时,攻击者有机会在新旧两个使用方之间建立时间窗口,使得一个请求仍然持有对已释放缓冲区的引用,而另一个请求已经获得了同一块物理内存。这种状态为后续的内存操作干预创造了条件。
第三阶段是越界写入(Out-of-Bounds Write)利用。Freelist 计数器的错误累积会导致系统认为存在比实际更多的空闲缓冲区。当内核尝试按计数分配缓冲区时,可能访问 freelist 数组末尾之后的内存位置,造成越界写入。这种越界写入能够破坏相邻的内核对象(如进程描述符、凭证结构、文件描述符表等),从而实现特权操作的劫持。
第四阶段是权限提升。攻击者可以通过精心设计的对象布局和内存喷射(Heap Spraying)技术,利用越界写入修改内核中的 credential 结构体,将当前进程的 UID、GID 等特权属性覆盖为 0(即 root 用户的标识)。这一步骤在传统的内核漏洞利用中通常需要借助信息泄露漏洞来泄漏内核对象地址,但在某些配置下,ZCRX 漏洞的利用可以结合内核堆喷技术直接达成目标。
值得注意的是,该漏洞的利用存在一定的前提条件。首先,目标系统必须启用 CONFIG_IO_URING_ZCRX 配置选项,这是 ZCRX 功能存在的必要条件。其次,攻击者通常需要具备一定的系统能力,包括创建 io_uring 实例和执行特定系统调用的权限。最后,利用效果受到内核版本和发行版配置的影响 —— 上游已在 6.15-6.19 区间推送修复,但各发行版的稳定内核是否包含该修复取决于具体的版本策略。
三、实际影响范围与漏洞管理现状
从漏洞管理角度,该问题的现状值得安全团队重点关注。首先是 CVE 编号的分配进度:截至目前,该漏洞已在 OSS-Security 邮件列表中提交 CVE 请求,但尚未获得正式的 CVE 编号。这一状态意味着漏洞的正式公开与补丁分发存在时间差,攻击者可能在此窗口期内进行在野利用。
其次是修复状态的差异。上游内核已在 commit 770594e 中添加了针对 freelist 违规的警告机制和边界检查,但该修复尚未完全合并至各发行版的稳定内核分支。对于使用 Ubuntu、RHEL、Debian 等发行版的企业环境,需要检查内核版本和安全公告,以确认是否已接收相关补丁。
最后是受影响系统的识别。由于漏洞仅在 CONFIG_IO_URING_ZCRX=y 时可被触发,安全团队可以通过检查内核配置文件或系统启动参数来评估暴露面。在容器化环境中,如果容器共享宿主机的内核(这是目前主流的容器运行时模式),则容器内的攻击者可以利用宿主机的内核漏洞实现逃逸,这对多租户云服务环境构成直接威胁。
四、可落地的缓解策略与监控参数
针对该漏洞的防护,安全团队可以从短期应急和长期治理两个层面采取行动。
在短期应急层面,首要任务是漏洞排查与版本升级。建议使用以下命令检查当前内核版本和 ZCRX 配置状态:在 Linux 系统中执行 uname -r 获取内核版本;通过 cat /boot/config-$(uname -r) | grep CONFIG_IO_URING_ZCRX 确认 ZCRX 是否启用。如果系统运行在内核 6.15 之前的版本且 CONFIG_IO_URING_ZCRX=y,应优先安排内核升级或与发行版供应商确认安全补丁的可用时间。
在无法立即升级内核的情况下,可考虑临时禁用 ZCRX 功能。io_uring 本身支持通过系统调用参数控制特定功能的启用,但更直接的方式是通过内核命令行参数或 sysctl 配置来限制 io_uring 的使用范围。对于不依赖 ZCRX 零拷贝接收的业务负载,禁用该功能可以消除直接的利用面。
在监控与检测层面,安全团队可以部署以下监控措施:利用内核审计子系统(auditd)监控 io_uring 相关系统调用的异常调用模式,特别是来自非特权用户的 io_uring_setup、io_uring_register 等操作;通过 eBPF 脚本追踪 io_zcrx_return_niov_freelist 函数的执行路径,检测同一缓冲区在短时间内的重复释放行为;结合内核崩溃转储(kdump)分析工具,收集潜在的利用尝试痕迹。
在长期治理层面,建议建立内核安全更新的标准流程,将内核安全补丁纳入常规的变更管理周期。由于内核漏洞的修复周期通常长于应用层漏洞,且可能涉及兼容性测试,强烈建议安全团队与运维团队协作,建立内核版本的基线管理和灰度发布机制。
五、总结
io_uring ZCRX freelist 漏洞代表了现代内核子系统在追求高性能的同时引入的新型攻击面。该漏洞通过精心设计的竞态条件,能够将看似普通的内存管理缺陷转化为本地权限提升的可行路径。其修复状态的不均衡分布(上游已修复但部分发行版尚未同步)进一步增加了实际环境中的风险敞口。对于运行容器化工作负载的云服务提供商和持有敏感数据的企业而言,本次漏洞提醒我们:内核子系统的安全性不仅影响单台主机,更直接关系到多租户隔离和容器逃逸防线的稳固性。建立覆盖内核配置检查、版本管理和异常行为监控的完整安全体系,已成为云原生时代安全运营的必备能力。
参考资料
- 安全研究人员 Mohamed Salem Eddah(ze3tar)在个人站点披露的漏洞详情与 PoC 状态:https://ze3tar.github.io/
- OSS-Security 邮件列表中关于 io_uring zcrx freelist OOB 写漏洞的 CVE 请求讨论:https://seclists.org/oss-sec/2026/q2/362
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。