Skip to content

QEMU eepro100 DMA-reentry stack overflow (CVE-2021-20255)

QEMU'nun emüle Intel i8255x (eepro100) NIC'inde guest-to-host bir denial of service; burada guest-programlanan DMA, device'ın controller-command handler'ına re-enter ederek host QEMU process'i stack'ini tüketene dek sınırsız recursion yapar.

Mechanism

Note

eepro100 modeli (hw/net/eepro100.c), guest-driven bir command block (CB) listesi işler: her command descriptor'ı guest memory'den DMA'lar, üzerinde işlem yapar ve bir sonrakine olan link'i izler. Örtük invariant, DMA read'lerin sıradan guest RAM'i hedeflemesi ve command işlemenin ileri ilerleme kaydetmesidir. CVE-2021-20255'te bir guest, controller'ı, bir command işlenirken yapılan bir DMA'nın device'ın kendi command-processing path'ine re-enter edeceği şekilde (bir DMA-reentrancy koşulu) programlayabilir. Bu path'te hiçbir şey derinliği sınırlamadığı ya da döngüyü kırmadığı için, handler her re-entry'de kendini geri çağırarak sınırsız bir recursion inşa eder. Host QEMU thread'inin call stack'i overflow edene dek büyür ve process'i abort eder. Corruption host'ta olduğu için, low-privileged bir guest guest→host sınırını bir denial of service olarak aşar (ve crash'ten önce yanan host CPU'su).

Bu, QEMU DMA-reentrancy UAF/loop ailesinin bir stack-exhaustion kardeşidir — qemu-e1000e-mmio-address-use-after-free içindeki heap-UAF şekliyle ve qemu-e1000-tx-descriptor-infinite-loop içindeki infinite-loop şekliyle karşılaştırın.

Walkthrough

Public, hâlihazırda patch'lenmiş advisory'den (oss-security, Red Hat / SUSE Bugzilla, upstream qemu-devel patch). Yalnızca kavramsal reproduction.

  1. Guest, eepro100'ü ayağa kaldırır ve kontrol ettiği memory'de bir command-block listesi inşa eder.
  2. DMA access'i (descriptor fetch / data move) device'a geri çözümlenen bir command ayarlar, böylece bir command'ı işlemek düz RAM'e dokunmak yerine controller-command routine'ine re-enter eder.
  3. Her re-entry, bir derinlik sınırı ya da cycle break olmadan command-processing call chain'inin bir başka frame'ini push eder — infinite recursion.
  4. Host QEMU thread'inin stack'i overflow edene dek büyür; process abort eder (guard page üzerinde SIGSEGV) — temiz bir host DoS.

Warning

Tarihsel, patch'lenmiş bir sorun (5.x dönemine kadar QEMU'yu etkiler). Bu giriş kavramsal kalır: tuning yapılmış bir recursion-depth primitive'i ya da herhangi bir escape değil, bug sınıfını ve invariant'ı adlandırır.

Reentrancy-guard concept (closes the class)
/* a device I/O dispatch refuses to recurse into itself */
if (dev->mem_reentrancy_guard.engaged_in_io) {
    return; /* drop / error the re-entrant access instead of recursing */
}
dev->mem_reentrancy_guard.engaged_in_io = true;
/* ... process command ... */
dev->mem_reentrancy_guard.engaged_in_io = false;

Detection

  • Host tarafı: bir stack-overflow imzasına sahip QEMU crash'i — backtrace'i derin, tekrarlanan eepro100 command-processing frame'leri (hw/net/eepro100.c) gösteren bir SIGSEGV; AddressSanitizer "stack-overflow" raporları.
  • Resource telemetry: QEMU process'i ölmeden hemen önce eepro100 path'inde bir vCPU'yu sürekli %100'e süren bir guest, güçlü bir DoS sinyalidir.
  • Behavioral: DMA target'ları RAM yerine device MMIO'ya çözümlenen NIC command-block descriptor'ları, herhangi bir meşru driver için anormaldir.

Mitigation

  • CVE-2021-20255 için upstream QEMU fix'ini uygulayın ve device mem_reentrancy_guard reentrancy korumasına sahip bir build çalıştırın (distro backport'ları: Debian, Ubuntu, Red Hat, SUSE).
  • Untrusted guest'ler için legacy emüle eepro100 yerine virtio-net'i tercih edin.
  • Defense-in-depth: QEMU'yu confine edin (seccomp, SELinux/sVirt, unprivileged kullanıcı) ve otomatik guest restart/quarantine politikalarını enable edin ki bir host DoS sınırlansın.

References

  • oss-security — CVE-2021-20255 (eepro100 stack overflow via infinite recursion): https://www.openwall.com/lists/oss-security/2021/02/25/1
  • Red Hat Bugzilla 1930646 — CVE-2021-20255: https://bugzilla.redhat.com/show_bug.cgi?id=1930646
  • SUSE Bugzilla 1182651 — CVE-2021-20255: https://bugzilla.suse.com/show_bug.cgi?id=1182651