
QEMU 11.1.2 - Alta - Local - UAF - NVMe SGL span na BAR0 incompleto CVE-2021-3929
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · qemu-nvme-sgl-bar
QEMU v11.1.2 (4fc49f46dc95d4a27de2509e7fceb2931e91faeb) - NVMe
Classe: UAF (deny-list incompleta de BAR0; SGL abrangente em DMA para MMIO). Alcance: Local (convidado).
nvme_map_addr é o resquício da CVE-2021-3929. A verificação de iomem é apenas no início. Um bloco de dados SGL que começa logo antes de BAR0 e avança para dentro de MBAR é aceito. O Identify ainda reporta NVME_CTRL_SGLS_SUPPORT_NO_ALIGN. PRP não pode abranger um BAR alinhado a página. SGL pode.
Um READ NVMe com esse SGL passa por nvme_blk_read -> dma_blk_read. O DMA de bounce então faz address_space_write dos bytes do disco do convidado sobre BAR0 a partir do callback do helper de DMA, fora do BH mem_reentrancy_guard do NVMe. Zeros escolhidos pelo convidado aterrissam em CC. nvme_ctrl_reset executa enquanto o NvmeRequest ativo ainda está no caminho de conclusão.
Um driver NVMe do convidado pode abranger SGL para dentro de BAR0, resetar o controlador a partir do unmap de DMA e correr com a requisição ativa.
| ID | ainda sem CVE |
| CWE | CWE-119 / CWE-416 |
| CVSS | Alto: 8.2 CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H |
| Produto | QEMU |
| Afetado | v11.1.2 (4fc49f46) |
| Autenticação | kernel do convidado com um controlador NVMe (SGL) |
| Licença | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1:18720 somente qtest |
Quem: kernel do convidado não confiável com um dispositivo PCI NVMe. Do convidado para o host.
| Método | Sink | Privilégio |
|---|---|---|
READ NVMe SGL addr=0xdfffffec len=0x1000 (começa 0x14 antes de BAR0 em 0xe0000000) | nvme_map_addr / nvme_addr_is_iomem somente no início | Mapeamento aceito. Identify de controle com início em BAR0 ainda retorna 0x4004 (DATA_TRAS_ERROR | DNR). |
Unmap de bounce escreve zeros de LBA sobre CC | address_space_write do bounce de DMA em BAR0, nvme_write_bar | CSTS.RDY cai. pci_nvme_mmio_stopped no log. Reset do controlador a partir do helper de DMA, não de um store MMIO do convidado no BH do NVMe. |
Bytes de disco controlados pelo convidado em CC / outros registradores de BAR0. O reset cancela AIOs em voo, mas a requisição que está dentro do unmap de DMA/conclusão ainda corre com o NvmeRequest / SQ / CQ ativos. Mesma classe da CVE-2021-3929; a deny-list nunca cobriu um SGL abrangente. O bounce de DIF (nvme_tx a partir de um callback de AIO) tem o mesmo buraco.
O controlador para (CSTS.RDY=0, mmio-stopped=1). O processo do hypervisor permanece ativo neste lab (asan=0). Um UAF de NvmeRequest por reset aninhado é o próximo passo inferido, não a testemunha que esta execução imprimiu.
Nenhum. BAR0 do NVMe é visível ao convidado.
0x4004.nvme_post_cqes é protegido, MMIO aninhado é MEMTX_ACCESS_ERROR.O lab não demonstra controle de RIP nem um shell do convidado para o host. A classe é DMA abrangente em MMIO mais reset do controlador de uma requisição ativa.
CVE-2021-3929 ensinou a árvore a rejeitar iomem como início de mapeamento NVMe. Perguntei se o fim de um bloco de dados SGL estava nesse teste. Não está. CMB/PMR já verificam ambas as extremidades. BAR0 não. Identify anuncia SGL desalinhado.
Caminhos errados: PRP (limitado por página, não consegue entrar furtivamente em um BAR alinhado a página a partir da página anterior); comandos admin (SGL rejeitado); esperar que o ASan disparasse na primeira READ (a testemunha é CSTS.RDY e pci_nvme_mmio_stopped, não um relatório de heap).
cd lab
./run.sh
Destino apenas 127.0.0.1:18720 (qtest). O pin é clonado de github.com/qemu/QEMU tag v11.1.2 / 4fc49f46. Loopback. Apenas testemunha. A imagem de disco é 1 MiB de zeros para que as escritas de bounce CC.EN=0.
SUCCESS qemu-nvme-sgl-bar control-sc=0x4004 span-addr=0xdfffffec span-end=0xe0000fec csts-rdy-before=1 csts-rdy-after=0 mmio-stopped=1 asan=0 QEMU-NVME-SGL-BAR-WITNESS
Replay: python3 qemu-nvme-sgl-bar-Abraxas-Labs.py.
Rejeitar um mapeamento se qualquer byte de [addr, addr+len) estiver em BAR0 (e MSI-X), correspondendo a CMB/PMR. nvme_addr_is_iomem deve receber um intervalo, não um início. Manter a rejeição de início em BAR0 como o controle da CVE-2021-3929.
4fc49f46dc95d4a27de2509e7fceb2931e91faebnvme_map_addr / nvme_addr_is_iomemGNU Affero GPL v3.0. Consulte LICENSE. Apenas laboratório loopback. Sem garantia.