Linux内核漏洞CVE-2022-29582分析与利用
漏洞概述
CVE-2022-29582是Linux内核io_uring子系统中的一个本地提权漏洞,影响版本从v5.10到v5.12的主线版本,5.10.109修复了此漏洞。漏洞评分7.0,属于条件竞争漏洞,涉及IORING_OP_TIMEOUT和IORING_OP_LINK_TIMEOUT操作。
漏洞环境
- 测试版本:Linux 5.10.90
- 关键编译选项:
CONFIG_E1000=y CONFIG_E1000E=y CONFIG_BINFMT_MISC=y CONFIG_TLS=y CONFIG_TLS_DEVICE=y CONFIG_TLS_TOE=y
补丁分析
补丁主要修改了io_flush_timeouts函数,使用list_for_each_entry_safe替代了原来的list_empty和list_first_entry组合,并移除了list_del_init调用。
io_uring基础
io_uring是Linux内核提供的高性能、低延迟I/O处理机制,主要组件:
- 提交队列(Submission Queue, SQ):存放I/O操作请求
- 完成队列(Completion Queue, CQ):存放已完成操作的结果
- 提交队列条目(SQE):编码单个I/O操作的结构体
关键结构体io_uring_sqe中,opcode字段指定I/O请求类型,如读取、写入、超时等。
Linked SQEs
通过设置SQE的flags字段中的IOSQE_IO_LINK标志,可以将多个SQE链接起来形成链。链中的操作按顺序执行,若链中任何操作失败,整个链都会失败。
超时操作
IORING_OP_TIMEOUT
设置超时时间T和可选完成事件计数C:
- 当超时时间T过去时:hrtimer启动,请求被取消并返回-ETIME
- 当完成事件计数C的其他请求已完成时:超时成功
IORING_OP_LINK_TIMEOUT
为特定操作设置超时:
- 如果超时时间过去:取消原始操作
- 如果原始操作已完成:取消超时操作
漏洞原理
漏洞源于将IORING_OP_TIMEOUT和IORING_OP_LINK_TIMEOUT操作放在同一链上时可能出现的竞争条件:
- 当T被销毁时,它保留了一个悬空引用指向LT
- 如果LT在T被销毁前被释放,会出现Use-After-Free情况
- 通过精心构造,可以将此UAF转化为提权漏洞
漏洞利用步骤
1. 替换LT对象
目标是用另一个对象LT'替换被释放的LT对象。由于堆隔离限制,LT'只能是另一个struct io_kiocb对象。
选择IORING_OP_TEE类型请求作为LT',因为:
- 可以通过
do_tee()从管道端读取来无限期阻塞 - 需要时可通过写入管道另一端恢复执行
2. 释放文件对象
通过精心构造虚假的文件对象,绕过filp_close()中的检查:
- 设置引用计数为1
- 设置
f_mode为FMODE_PATH - 设置
f_op指向特定地址使f_op->flush为NULL
3. 跨缓存攻击
由于文件对象有自己的专用缓存(filp),需要通过以下步骤将页面释放回页面分配器:
- 填满缓存中正在使用的所有页面
- 释放目标页面上的所有对象
- 触发
unfreeze_partials()将空页面释放回页面分配器
4. 页面重新分配
将释放的页面重新分配到kmalloc-512缓存,使用msg_msgseg对象覆盖文件对象。
5. 信息泄露
通过喷射tls_context对象并读取其内容来获取内核地址:
tls_context中的list_head指向自身sk_proto指向tcp_prot,可用于计算内核基址
6. 代码执行
-
准备伪造的
tls_context数据:- 包含ROP链
- 覆盖
sk_proto为tls_context地址 - 覆盖
getsockopt()为栈旋转gadget地址
-
触发执行:
- 调用
getsockopt()触发栈迁移 - ROP链开始执行,完成提权
- 调用
参考链接
利用代码
原作者提供的利用代码可从以下链接获取:
下载链接
登录用户名: hi
密码: lol
总结
CVE-2022-29582是一个复杂的条件竞争漏洞,涉及io_uring子系统的超时处理机制。通过精心构造的竞争条件和多阶段的堆操作,攻击者可以将此漏洞转化为可靠的提权漏洞。防御此类漏洞需要及时更新内核版本,并考虑使用更安全的编程模式来处理异步操作和资源释放。