Skip to content

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.

  1. Guest, emule edilmiş OHCI controller'ını sürer ve crafted frame-count / offset field'larına sahip bir isochronous transfer descriptor'ı queue'lar.

  2. Frame processing (ohci_frame_boundaryohci_service_ed_listohci_service_iso_td), guest field'larından relative_frame_number'ı hesaplar ve bunu descriptor'ın offset[] array'ini index'lemek ve bir buffer len'i türetmek için kullanır.

    Conceptual shape (not a working exploit)
    ohci_frame_boundary()
      -> ohci_service_ed_list()
           -> ohci_service_iso_td()
                # relative_frame_number from guest fields, under-checked
                -> read iso_td.offset[relative_frame_number + 1]   # OOB on stack
                -> derive len (uncapped) -> over-read into usb_buf
    
  3. 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_count check'lerini ekler, start_addr/end_addr sıralamasını validate eder ve len'i sizeof(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 READ rapor 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 on seccomp, unprivileged uid, SELinux/sVirt) çalıştır.
  • Build hardening: QEMU'yu stack protector ve _FORTIFY_SOURCE ile 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.

References