QEMU OHCI USB stack over-read (CVE-2020-25624)¶
QEMU'nun OHCI USB controller'ı, guest driver tarafından sağlanan isochronous transfer-descriptor field'larını bound etmeden okuyor; sabit boyutlu, stack üzerindeki bir array'i range dışında index'liyor — host QEMU process'ini crash'leyebilen stack tabanlı bir buffer over-read.
Mechanism¶
Isolation invariant: guest tarafından sağlanan descriptor index'leri, host array'leri index'lemeden önce bound edilmeli
OHCI, USB işini guest memory'sinde yaşayan descriptor'lardan işler. Isochronous transfer'ler için controller, guest-controlled field'lardan bir relative_frame_number hesaplar ve bunu, QEMU'nun host stack'ine okuduğu isochronous transfer descriptor'ı içindeki sabit boyutlu bir offset[] array'ini index'lemek için kullanır. Invariant: guest data'sından türetilen herhangi bir index, kullanılmadan önce array'in sınırlarına karşı validate edilmeli.
Vulnerable kodda (hw/usb/hcd-ohci.c içindeki ohci_service_iso_td()), frame index'i ve türetilen transfer length'i tam olarak clamp edilmemişti. Crafted bir descriptor, controller'ın stack üzerindeki structure'ın sonunun ötesinde iso_td.offset[relative_frame_number + 1] okumasını (ve bir len hesaplamasını) sağlayarak komşu host stack memory'sini okuyabilirdi. OHCI model'i host QEMU process'inde çalıştığı için bu, host tarafında bir stack over-read'tir (CWE-125) — guest RAM access'i değil, bir information/stability sınır aşımı. Read/write primitive çerçevelemesi için bkz. ../primitive/information-leak-memory-disclosure.md ve ../primitive/out-of-bounds-write.md.
Walkthrough¶
CVE-2020-25624 olarak disclose ve patch edildi (hw/usb/hcd-ohci.c, QEMU 5.0.0; 5.2.0 için düzeltildi). Fix, frame index'i ve transfer length'i üzerine bounds check'leri ekler. Aşağıdaki path kavramsaldır, public patch thread'inden alınmıştır.
-
Guest, emule edilmiş OHCI controller'ını sürer ve crafted frame-count / offset field'larına sahip bir isochronous transfer descriptor'ı queue'lar.
-
Frame processing (
ohci_frame_boundary→ohci_service_ed_list→ohci_service_iso_td), guest field'larındanrelative_frame_number'ı hesaplar ve bunu descriptor'ınoffset[]array'ini index'lemek ve bir bufferlen'i türetmek için kullanır. -
Check edilmeyen index/length, stack üzerindeki descriptor'ın ötesini okur (ve
usb_buf'a fazla uzun kopyalar yapar). QEMU fault'a girer ya da bozuk data'yı yanlış handle eder ve process'i crash'ler (DoS). Patch,relative_frame_number < frame_countcheck'lerini ekler,start_addr/end_addrsıralamasını validate eder velen'isizeof(ohci->usb_buf)'a cap'ler.
Tarihsel / patch'lenmiş
Yalnızca yetkili defensive research ve regression testing içindir. Fragment missing-bounds-check şeklini gösterir, weaponize edilmiş bir chain'i değil. Patch'lenmemiş QEMU'ya karşı untrusted guest'ler çalıştırma.
Detection¶
- Crash signature:
ohci_service_iso_td/ohci_service_ed_list/ohci_frame_boundaryüzerinden geçen bir backtrace'e sahip bir QEMU SIGSEGV/abort, kanonik fingerprint'tir. - ASAN/stack-protector build'leri: bir sanitizer QEMU build'i, OHCI ISO TD processing'inde köklenen bir
stack-buffer-overflow READrapor eder; bir stack-protector build'i, over-copy varyantında*** stack smashing detected ***ile abort edebilir. - Telemetry: bir guest'in out-of-range frame count/offset'lere sahip OHCI isochronous descriptor'ları queue'laması anormaldir ve USB/qtest tracing (
trace_usb_ohci_*) üzerinden gözlemlenebilir. - Fuzzing: OHCI descriptor field'larını mutate eden USB-HCD device fuzzing bu class'ı reproduce eder. Bkz. ../hypervisor/hypercall-fuzzing.md ve ilgili USB kayıtları ../hypervisor/qemu-usb-usb-process-one-out-of-bounds-r-w-vm-escape.md.
Mitigation¶
- Patch: OHCI length/frame-number bounds check'lerini taşıyan QEMU 5.2.0 veya sonrasına (ya da bir distro backport'una) güncelle.
- Defense in depth: gerekli olmadığında untrusted guest'lere emule edilmiş bir OHCI controller'ı expose etme; XHCI/virtio'yu tercih et ya da machine type'ta USB'yi tamamen çıkar.
- Confinement: abort olmuş bir device model'i sınırlamak için QEMU'yu sandbox'lanmış olarak (
-sandbox onseccomp, unprivileged uid, SELinux/sVirt) çalıştır. - Build hardening: QEMU'yu stack protector ve
_FORTIFY_SOURCEile dağıt; böylece bir over-read/over-copy sessizce sızdırmak yerine temiz şekilde abort olmaya daha yatkın olur. - Operational: guest-triggered bir host QEMU crash'ini bir security event olarak ele al.