🔍 CVE-2024-53169

9.8
CVSS Score
CRITICAL
2024-12-27
2026-08-04 11:22
✅ 완료

🇰🇷 한글 설명

Linux 커널의 nvme-fabrics 구성 요소에서 컨트롤러 종료 시 발생하는 레이스 컨디션 취약점입니다. 컨트롤러가 종료되는 동안 nvme keep-alive 작업이 동시에 실행되면서 이미 삭제된 관리 큐(admin queue) 자원에 접근하여 커널 크래시를 유발할 수 있습니다.

💡 쉬운 설명

컴퓨터의 저장 장치 연결을 끊는 과정에서, 연결 상태를 확인하는 작업이 동시에 실행되어 시스템이 충돌하는 문제입니다. 이로 인해 시스템이 갑자기 멈추거나 재부팅될 수 있습니다.

🇺🇸 원문 (English)

In the Linux kernel, the following vulnerability has been resolved: nvme-fabrics: fix kernel crash while shutting down controller The nvme keep-alive operation, which executes at a periodic interval, could potentially sneak in while shutting down a fabric controller. This may lead to a race between the fabric controller admin queue destroy code path (invoked while shutting down controller) and hw/hctx queue dispatcher called from the nvme keep-alive async request queuing operation. This race could lead to the kernel crash shown below: Call Trace: autoremove_wake_function+0x0/0xbc (unreliable) __blk_mq_sched_dispatch_requests+0x114/0x24c blk_mq_sched_dispatch_requests+0x44/0x84 blk_mq_run_hw_queue+0x140/0x220 nvme_keep_alive_work+0xc8/0x19c [nvme_core] process_one_work+0x200/0x4e0 worker_thread+0x340/0x504 kthread+0x138/0x140 start_kernel_thread+0x14/0x18 While shutting down fabric controller, if nvme keep-alive request sneaks in then it would be flushed off. The nvme_keep_alive_end_io function is then invoked to handle the end of the keep-alive operation which decrements the admin->q_usage_counter and assuming this is the last/only request in the admin queue then the admin->q_usage_counter becomes zero. If that happens then blk-mq destroy queue operation (blk_mq_destroy_ queue()) which could be potentially running simultaneously on another cpu (as this is the controller shutdown code path) would forward progress and deletes the admin queue. So, now from this point onward we are not supposed to access the admin queue resources. However the issue here's that the nvme keep-alive thread running hw/hctx queue dispatch operation hasn't yet finished its work and so it could still potentially access the admin queue resource while the admin queue had been already deleted and that causes the above crash. The above kernel crash is regression caused due to changes implemented in commit a54a93d0e359 ("nvme: move stopping keep-alive into nvme_uninit_ctrl()"). Ideally we should stop keep-alive before destroyin g the admin queue and freeing the admin tagset so that it wouldn't sneak in during the shutdown operation. However we removed the keep alive stop operation from the beginning of the controller shutdown code path in commit a54a93d0e359 ("nvme: move stopping keep-alive into nvme_uninit_ctrl()") and added it under nvme_uninit_ctrl() which executes very late in the shutdown code path after the admin queue is destroyed and its tagset is removed. So this change created the possibility of keep-alive sneaking in and interfering with the shutdown operation and causing observed kernel crash. To fix the observed crash, we decided to move nvme_stop_keep_alive() from nvme_uninit_ctrl() to nvme_remove_admin_tag_set(). This change would ensure that we don't forward progress and delete the admin queue until the keep- alive operation is finished (if it's in-flight) or cancelled and that would help contain the race condition explained above and hence avoid the crash. Moving nvme_stop_keep_alive() to nvme_remove_admin_tag_set() instead of adding nvme_stop_keep_alive() to the beginning of the controller shutdown code path in nvme_stop_ctrl(), as was the case earlier before commit a54a93d0e359 ("nvme: move stopping keep-alive into nvme_uninit_ctrl()"), would help save one callsite of nvme_stop_keep_alive().

📍 영향받는 시스템

Linux kernel (nvme-fabrics module 사용 환경)

⚔️ 공격 벡터

로컬 또는 네트워크를 통한 특정 타이밍의 NVMe 컨트롤러 종료 유도 (Race Condition)

🛡️ 대응 방법

커널 패치를 통해 nvme_stop_keep_alive() 호출 시점을 조정하여 관리 큐 삭제 전 keep-alive 작업이 완료되도록 수정해야 합니다.

🔧 검증 코드

출력된 커널 버전이 취약점이 해결된 최신 패치 버전인지 확인합니다.

Shell / Script
uname -r

📊 CVSS Vector String

CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

💻 영향받는 소프트웨어

Linux Kernel