CVE-2022-50550CVE-2022-50550是Linux内核blk-iolatency子系统中的一个内存泄漏漏洞。当gendisk成功初始化但add_disk()调用失败时(例如loop设备指定了无效的次设备号数量),系统会在初始化阶段调用blkcg_init_disk(),然后在错误处理阶段调用blkcg_exit_disk()。然而,iolatency在blkcg_init_disk()中被初始化,但在blkcg_exit_disk()的错误处理路径中并未被正确清理,导致内存泄漏。
在正常情况下,iolatency的清理是通过del_gendisk()调用rq_qos_exit()来完成的,其前提假设是rq_qos策略(包括iolatency)只有在磁盘完全注册并可见后才能被激活。这一假设对于wbt和iocost是成立的,但对于iolatency并不成立,因为iolatency在add_disk()被调用之前就已经被初始化了。
该漏洞的CVSS评分为5.5,属于中等严重级别。攻击向量为本地攻击(AV:L),需要低权限(PR:L),无需用户交互(UI:N),对机密性影响为低(C:L),对完整性无影响(I:N),对可用性影响为高(A:H)。该漏洞可能导致内核内存资源耗尽,影响系统稳定性和可用性。
该漏洞的技术原理涉及Linux内核块设备层的资源管理机制。具体来说:
1. **初始化流程**:当创建一个新的gendisk时,内核会调用blkcg_init_disk()来初始化blkcg相关的资源,其中包括iolatency策略的初始化(通过调用rq_qos_init()或类似函数)。
2. **错误处理路径**:如果add_disk()调用失败(例如loop设备的次设备号数量无效),内核会进入错误处理路径,调用blkcg_exit_disk()来清理blkcg资源。然而,blkcg_exit_disk()并未调用rq_qos_exit()来清理iolatency策略。
3. **设计假设问题**:在正常(非错误)情况下,iolatency的清理由del_gendisk()通过调用rq_qos_exit()完成。这是因为设计上假设rq_qos策略只能在磁盘完全注册并可见后才被激活。然而,这个假设对于iolatency并不成立——iolatency在add_disk()被调用之前就已经被初始化了。
4. **根本原因**:blkcg_exit_disk()缺少对rq_qos_exit()的调用,导致在错误路径上iolatency相关的内存资源无法被释放。
5. **利用方式**:攻击者可以通过反复触发add_disk()失败的情况(例如通过加载loop设备模块并指定无效的次设备号参数),导致内核内存持续泄漏,最终可能耗尽系统内存资源,引发拒绝服务(DoS)攻击。
6. **修复方案**:在blkcg_exit_disk()中添加对rq_qos_exit()的额外调用。由于重复调用rq_qos_exit()是安全的(会变成noop),这种修复方式不会引入新的问题。长期来看,应该将iolatency改为延迟初始化(lazy init),但这是一个更大的改动。