漏洞背景
2025年6月初,我在审查Linux内核新功能时了解到面向流的UNIX域套接字支持的MSG_OOB特性。在审查MSG_OOB实现时,发现了影响Linux >=6.9的安全漏洞CVE-2025-38236。该漏洞已向Linux报告并修复。
有趣的是,虽然Chrome不使用MSG_OOB功能,但它在Chrome渲染器沙箱中暴露了出来。(此后,Chrome渲染器中已阻止发送MSG_OOB消息作为对此问题的响应。)
漏洞触发
该漏洞很容易触发,以下序列会导致UAF:
|
|
MSG_OOB特性分析
2021年通过commit 314001f0bf92(在Linux 5.15中落地)添加了对AF_UNIX流套接字使用MSG_OOB的支持。该功能非常有限 - 带外数据始终是单个字节,一次只能有一个待处理的带外数据字节。
当消息在两个连接的面向流套接字之间发送时,消息被添加到接收套接字的->sk_receive_queue
中,这是一个链表。MSG_OOB消息也像普通消息一样添加到->sk_receive_queue
;但为了允许接收套接字提前访问最新的带外消息,接收套接字的->oob_skb
指针会更新指向此消息。
漏洞原理
2024年中发现了一个用户空间API不一致性问题,当尝试从包含由接收OOB SKB留下的剩余长度0 SKB的接收队列读取时,recv()可能虚假返回0。修复此问题的补丁引入了两个密切相关的可导致UAF的安全问题。
漏洞的根本原因是:当接收队列包含由recv(…, MSG_OOB)留下的剩余长度0 SKB时,manage_oob()会跳过到下一个SKB,并假设它也不是剩余长度0 SKB。如果这个假设被打破,manage_oob()可能返回指向第二个剩余长度0 SKB的指针,这很糟糕,因为调用者unix_stream_read_generic()不希望看到剩余长度0 SKB。
利用技术
初始原语
该漏洞产生一个悬空的->msg_oob
指针。唯一的使用方式是通过带有MSG_OOB的recv()系统调用,这提供了:
- 读取原语:通过
copy_to_user(<用户空间指针>, <内核指针>, 1)
可以重复使用任意内核指针读取一个字节数据 - 写入原语:当MSG_PEEK未设置时,对
UNIXCB(oob_skb).consumed
进行递增操作
利用策略
由于该问题相对直接地导致半任意读取,但写入原语更加复杂,决定采用以下通用方法:首先使读取原语工作;然后使用读取原语辅助利用写入原语。
关键技术点
- 处理每CPU状态:利用依赖于每CPU内核数据结构,需要处理任务迁移问题
- 设置读取原语:通过SLUB缓存喷射和管道页重分配技术
- 内核映像定位:通过读取中断描述符表(IDT)条目突破KASLR
- 写入原语目标选择:利用CONFIG_RANDOMIZE_KSTACK_OFFSET特性,将目标页重分配为内核栈页
- 延迟注入:使用mprotect()操作大型匿名VMA来延迟copy_from_user()调用
沙箱攻击面分析
在利用过程中能够使用相当多的内核接口,包括:
- 匿名VMA创建和页面表分配
- AF_UNIX套接字操作
- 管道操作
- 线程同步原语
- 内存管理操作等
结论与启示
- Chrome沙箱攻击面:暴露了沙箱中从未合法使用的内核攻击面
- 内核特性安全:核心内核子系统中的冷门特性往往比核心功能更容易出现bug
- 概率性防护:面对具有任意读取能力的攻击者时,概率性缓解措施可能无效
- 模糊测试限制:复杂数据结构的安全性规则对模糊测试构成挑战
- 用户拷贝硬化:虽然造成困扰,但可以通过访问其他可读内存来绕过
即使在受限环境中,也有可能完成中等复杂度的Linux内核漏洞利用。Chrome的Linux桌面渲染器沙箱暴露了不必要的内核功能,这不仅允许攻击者利用他们 otherwise 无法触发的漏洞,还暴露了对利用有用的内核接口。