🇰🇷 한글 설명
Linux 커널의 nvmet: pci-epf 구성 요소에서 nvmet_req_init() 함수가 실패할 경우 명령을 중복으로 완료하는 취약점이 발견되었습니다. 이로 인해 호스트에 두 번의 완료 신호가 전송되고 PCI NVMe 타겟의 상태가 손상되어 커널 Oops(시스템 오류)가 발생할 수 있습니다.
💡 쉬운 설명
지원하지 않는 명령을 보냈을 때 시스템이 '작업 완료' 신호를 두 번 보내는 오류가 있습니다. 이 과정에서 시스템 내부 데이터가 꼬여 컴퓨터가 갑자기 멈추거나 오류를 일으킬 수 있습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
nvmet: pci-epf: Do not complete commands twice if nvmet_req_init() fails
Have nvmet_req_init() and req->execute() complete failed commands.
Description of the problem:
nvmet_req_init() calls __nvmet_req_complete() internally upon failure,
e.g., unsupported opcode, which calls the "queue_response" callback,
this results in nvmet_pci_epf_queue_response() being called, which will
call nvmet_pci_epf_complete_iod() if data_len is 0 or if dma_dir is
different from DMA_TO_DEVICE. This results in a double completion as
nvmet_pci_epf_exec_iod_work() also calls nvmet_pci_epf_complete_iod()
when nvmet_req_init() fails.
Steps to reproduce:
On the host send a command with an unsupported opcode with nvme-cli,
For example the admin command "security receive"
$ sudo nvme security-recv /dev/nvme0n1 -n1 -x4096
This triggers a double completion as nvmet_req_init() fails and
nvmet_pci_epf_queue_response() is called, here iod->dma_dir is still
in the default state of "DMA_NONE" as set by default in
nvmet_pci_epf_alloc_iod(), so nvmet_pci_epf_complete_iod() is called.
Because nvmet_req_init() failed nvmet_pci_epf_complete_iod() is also
called in nvmet_pci_epf_exec_iod_work() leading to a double completion.
This not only sends two completions to the host but also corrupts the
state of the PCI NVMe target leading to kernel oops.
This patch lets nvmet_req_init() and req->execute() complete all failed
commands, and removes the double completion case in
nvmet_pci_epf_exec_iod_work() therefore fixing the edge cases where
double completions occurred.
📍 영향받는 시스템
Linux kernel (nvmet: pci-epf 구성 요소 사용 시스템)
⚔️ 공격 벡터
nvme-cli 등을 사용하여 지원되지 않는 Opcode(예: security receive)를 포함한 명령을 호스트에서 전송
🛡️ 대응 방법
nvmet_req_init() 및 req->execute()의 실패 처리 로직이 수정된 최신 Linux 커널로 업데이트
🔧 검증 코드
출력된 커널 버전이 해당 취약점이 패치된 최신 버전인지 확인합니다.