Skip to content

QEMU xHCI TRB-ring infinite loop (CVE-2020-14394)

Guest tarafından hazırlanmış, length hesabı asla sonlanmayan bir USB transfer ring'i QEMU'nun xHCI emulation'ını sonsuza dek döndürür ve host CPU'sunu kilitler — bir guest-to-host denial of service.

Mechanism

Sınır neden kırılıyor

QEMU, USB 3.0 xHCI host controller'ını (hw/usb/hcd-xhci) host process içinde emüle eder. Controller, işi Transfer Request Blocks (TRBs) üzerinden zamanlar; bunlar ring'ler hâlinde organize edilir: ardışık TRB segment'leri, bir sonraki segment'e işaret eden Link TRBs ile birbirine dikilir. QEMU, bir transfer'i işlemeden önce ring'i dolaşarak chain length'ini hesaplar, Link TRB'leri bir segment'ten diğerine sona ulaşana kadar takip eder.

Hata şu ki ring layout'u — segment pointer'ları ve Link TRBs — tamamen guest-controlled'dür ve length sayan walk'un ne kadar ileri gideceğine dair hiçbir sınırı yoktu. Privileged bir guest, Link TRB'lerinin bir cycle (ya da fiilen sonsuz bir chain) oluşturduğu bir ring inşa edebilir, böylece walk asla sonlandırıcı bir descriptor'a ulaşmaz. Bu, ulaşılamaz bir exit condition'a sahip bir loop'tur (CWE-835): hiçbir şey overwrite edilmez ama ring'i sayan host vCPU/QEMU thread'i sonsuza dek döner. İhlal edilen invariant şudur: guest-supplied pointer'lar tarafından sürülen bir traversal bounded olmalıdır — sert bir iteration cap ile ya da yeniden ziyaret edilen segment'leri saptayarak — ki emulation her zaman sonlansın. Etki: privileged bir guest, QEMU process'ini hang'ler. Bu, şuradaki ile aynı liveness fault class'ıdır: qemu-lsi53c895a-scsi-infinite-loop.md ve qemu-coldfire-fec-infinite-loop.md.

Walkthrough

Public NVD kaydı, Red Hat Bugzilla ve QEMU GitLab issue'sundan kavramsal yeniden inşa; yalnızca mantıksal adımlar.

  1. Privileged bir guest driver, xHCI controller'ını programlar ve guest memory'de bir TRB ring yerleştirir, segment'leri chain'lemek için Link TRB'leri kullanır.
  2. Guest, Link TRB'lerini birbirine referans verecek şekilde ayarlar ki chain sonlanmak yerine geri döngüye girsin, ya da başka türlü asla bir end-of-ring marker'ına ulaşmasın.
  3. Guest doorbell'i çalar. QEMU'nun xhci_ring_chain_length() fonksiyonu (hw/usb/hcd-xhci.c içinde) TRB'leri saymak için ring'i dolaşır, guest'in Link TRB'lerini takip eder.
  4. Walk'un exit'i yalnızca guest-controlled pointer'lara bağlı olduğu için asla sonlanmaz — host QEMU thread'i ilerleme olmadan %100'de döner (DoS).
Root cause ve fix şekli (illustrative)

Length walk, bir cap olmadan Link TRB'leri takip ediyordu:

/* count TRBs by following the guest's ring; loop exit depends on
   guest-controlled Link TRBs -> can be made non-terminating */
while (TRB_TYPE(trb) == TR_LINK) {
    ring->dequeue = xhci_ring_link(...);   /* guest pointer */
    /* ... no bound on iterations / no cycle detection ... */
}

Fix, traversal'ı bound'lar ki kötü niyetli bir ring sonsuza dek döngüye giremesin (length walk'un takip edeceği segment/iteration sayısını cap'leyerek).

"An infinite loop flaw was found in the USB xHCI controller emulation of QEMU ... while computing the length of the Transfer Request Block (TRB) Ring. This flaw allows a privileged guest user to hang the QEMU process on the host, resulting in a denial of service." — NVD CVE-2020-14394

Detection

  • Host CPU spin: I/O ilerlemesi olmadan %100'e sabitlenmiş bir QEMU/vCPU thread'i, guest'in emüle xHCI (USB 3.0) controller'ını kullanmasıyla ilişkilendirildiğinde, birincil sinyaldir (top/perf, hung-task watchdog'ları).
  • Stack inspection: Bir debugger attach etmek, host thread'inin xHCI ring-walk / xhci_ring_chain_length path'inde döngüye girdiğini gösterir.
  • Telemetry: xHCI ring'lerini programlayıp ardından anında, sürekli bir host-thread hang'i gelen guest aktivitesi anomalidir ve device-model logging ile per-vCPU CPU accounting tarafından yüzeye çıkarılabilir.

Mitigation

  • Patch: TRB-ring length traversal'ını bound'layan upstream QEMU fix'ini (QEMU GitLab issue #646 ve Red Hat Bugzilla #1908004'te izleniyor) uygula ki guest tarafından hazırlanmış bir ring sonsuza dek döngüye giremesin.
  • Attack surface'i azalt: xHCI controller'ı yalnızca USB 3.0'a ihtiyaç duyan guest'ler için attach et; gereken minimal USB topology'sini tercih et ve emüle controller'ları gereksiz yere untrusted guest'lere açmaktan kaçın.
  • Host etkisini cap'le: QEMU'yu seccomp (-sandbox on) ve svirt confinement altında çalıştır; QEMU process'ine cgroup CPU quota'ları uygula ki kontrolden çıkmış bir emulation thread'i, patch'lemeden önce bile host'un geri kalanını aç bırakamasın.

References