
QEMU 11.1.2 - Alta - Locale - UAF - NVMe SGL span in 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 BAR0 incompleta; SGL DMA che si estende in MMIO). Portata: Locale (guest).
nvme_map_addr è ciò che resta di CVE-2021-3929. Il controllo iomem è solo sull'indirizzo iniziale. Un blocco dati SGL che inizia poco prima di BAR0 e si estende in MBAR viene accettato. Identify riporta comunque NVME_CTRL_SGLS_SUPPORT_NO_ALIGN. PRP non può estendersi su una BAR allineata a pagina. SGL sì.
Una READ NVMe con quell'SGL passa per nvme_blk_read -> dma_blk_read. Il bounce DMA esegue poi address_space_write dei byte del disco guest su BAR0 dal callback dell'helper DMA, al di fuori del BH mem_reentrancy_guard di NVMe. Gli zeri scelti dal guest finiscono su CC. nvme_ctrl_reset viene eseguito mentre il NvmeRequest attivo è ancora nel percorso di completamento.
Un driver NVMe guest può estendere un SGL in BAR0, resettare il controller dall'unmap DMA e correre contro la richiesta attiva.
| ID | nessun CVE al momento |
| 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 |
| Prodotto | QEMU |
| Affetto | v11.1.2 (4fc49f46) |
| Auth | kernel guest con un controller NVMe (SGL) |
| Licenza | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1:18720 solo qtest |
Chi: kernel guest non fidato con un dispositivo PCI NVMe. Da guest a host.
| Metodo | Sink | Privilegio |
|---|---|---|
READ NVMe SGL addr=0xdfffffec len=0x1000 (inizia 0x14 prima di BAR0 a 0xe0000000) | nvme_map_addr / nvme_addr_is_iomem solo sull'inizio | Mapping accettato. Control Identify con inizio in BAR0 restituisce comunque 0x4004 (DATA_TRAS_ERROR | DNR). |
L'unmap del bounce scrive zeri LBA su CC | address_space_write del bounce DMA in BAR0, nvme_write_bar | CSTS.RDY scende. pci_nvme_mmio_stopped nel log. Reset del controller dall'helper DMA, non da un MMIO store del guest nel BH NVMe. |
Byte del disco controllati dal guest su CC / altri registri BAR0. Il reset annulla gli AIO in volo, ma la richiesta che è dentro l'unmap/completamento DMA corre comunque contro il NvmeRequest / SQ / CQ attivi. Stessa classe di CVE-2021-3929; la deny-list non ha mai coperto un SGL che si estende. Il bounce DIF (nvme_tx da un callback AIO) ha lo stesso buco.
Il controller si ferma (CSTS.RDY=0, mmio-stopped=1). Il processo dell'hypervisor resta attivo in questo lab (asan=0). Un UAF da reset annidato di NvmeRequest è il passo successivo inferito, non il witness stampato da questa esecuzione.
Nessuna. BAR0 NVMe è visibile al guest.
0x4004.nvme_post_cqes è protetto, l'MMIO annidato è MEMTX_ACCESS_ERROR.Il lab non dimostra il controllo di RIP né una shell da guest a host. La classe è DMA che si estende in MMIO più reset del controller di una richiesta attiva.
CVE-2021-3929 ha insegnato all'albero a rifiutare iomem come inizio di una mappatura NVMe. Ho chiesto se la fine di un blocco dati SGL fosse inclusa in quel test. Non lo è. CMB/PMR controllano già entrambe le estremità. BAR0 no. Identify segnala SGL non allineato.
Vicoli ciechi: PRP (limitato alla pagina, non può introdursi in un BAR allineato alla pagina dalla pagina precedente); comandi admin (SGL rifiutato); sperare che ASan scattasse alla prima READ (il testimone è CSTS.RDY e pci_nvme_mmio_stopped, non un report dell'heap).
cd lab
./run.sh
Prendi di mira solo 127.0.0.1:18720 (qtest). Il pin è clonato da github.com/qemu/QEMU tag v11.1.2 / 4fc49f46. Loopback. Solo testimone. L'immagine del disco è 1 MiB di zeri, così il bounce scrive 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.
Rifiutare una mappatura se un qualsiasi byte di [addr, addr+len) risiede in BAR0 (e MSI-X), in modo coerente con CMB/PMR. nvme_addr_is_iomem dovrebbe accettare un intervallo, non un indirizzo iniziale. Mantenere il rifiuto dell'indirizzo iniziale in BAR0 come controllo per CVE-2021-3929.
4fc49f46dc95d4a27de2509e7fceb2931e91faebnvme_map_addr / nvme_addr_is_iomemGNU Affero GPL v3.0. Vedi LICENSE. Solo laboratorio su loopback. Nessuna garanzia.