Skip to content

QEMU floppy FDC NULL pointer deref (CVE-2021-20196)

Privileged bir guest, uninitialized bir floppy drive seçip FDC emulator'ünü bir NULL pointer dereference'a sürebilir ve host QEMU process'ini crash'letebilir (guest-to-host DoS).

Mechanism

Bug sınıfı: guest-selectable bir index üzerinde kontrol edilmemiş device-backing pointer

QEMU'nun floppy disk controller'ı (FDC), bir drive struct dizisi tutar. Her drive, VM yapılandırmasına bağlı olarak host tarafında bir block backend'e (BlockBackend *blk) sahip olabilir ya da olmayabilir. Emulator'ün tutması gereken invariant şudur: o anda seçili drive'ın blk'ini dereference eden her kod path'i, önce gerçekten bir block device'ın attach edildiğini doğrulamalıdır.

Digital Output Register (DOR), guest'in bir ioport yazmasıyla (FD_REG_DOR -> fdctrl_write_dor()) hangi drive'ın "current" olduğunu seçmesine izin verir. Yazılan değerin düşük bit'leri (value & FD_DOR_SELMASK) doğrudan drive dizisini index'ler ve aktif drive'ı ayarlar. Bir guest dolayısıyla bir backend ile hiç initialize edilmemiş bir drive slot'unu seçebilir. Sonraki bir read/write ioport komutu (fdctrl_read_data() / fdctrl_write_data()) çalıştığında, cur_drv->blk'e uzanır ve emulator bir NULL pointer dereference eder.

Security boundary aşılır çünkü guest selector'ı tamamen kontrol eder (mimari olarak meşru bir I/O port yazması), ancak host kodu seçili drive'ın backed olduğuna güvendi. Sonuç, guest tarafından çıkarılan well-formed bir operasyondan kaynaklanan host tarafı bir crash'tir — memory corruption yok, ama virtualization sınırı boyunca temiz bir availability kırılması.

Walkthrough

Public advisory'den ve upstream "check drive block device before usage" patch'inden alınan üst düzey, kavramsal reproduction.

  1. Guest, slot'unun blk backend'i attach edilmemiş bir drive index'i seçerek FDC Digital Output Register'ına bir ioport yazması yapar.
Conceptual selection + trigger (logical fragments, not an exploit)
# Guest side (conceptual): point the DOR selector at an un-backed drive,
# then issue a data-phase read/write that touches the drive backend.
outb(FDC_DOR_PORT,  <value selecting an un-initialized drive slot>)
inb (FDC_DATA_PORT)        # data-phase read -> fdctrl_read_data()
  1. QEMU içinde, fdctrl_write_dor() current-drive pointer'ını tamamen guest tarafından sağlanan selector bit'lerinden günceller.

  2. Data-phase handler'ı ardından blk == NULL iken cur_drv->blk'i block-layer koduna kadar izler, NULL'u dereference eder ve QEMU process'ini abort eder.

Bir guest buna nasıl ulaşıyor

Path yalnızca standart, belgelenmiş FDC I/O port'larını kullanır. Emüle FDC'ye port I/O yapabilen herhangi bir guest context'i (tipik olarak guest içinde privileged) ona ulaşabilir; egzotik bir state machine kurulumu gerekmez.

Fix, un-backed bir drive'ın asla aktif olarak ele alınmaması için defansif guard'lar ekler:

/* Conceptual shape of the upstream fix (paraphrased) */
/* fdctrl_write_dor(): only switch current drive if it has a backend */
if (fdctrl->drives[value & FD_DOR_SELMASK].blk != NULL) {
    /* update selected drive */
}

/* fdctrl_read_data()/fdctrl_write_data(): bail out early if !cur_drv->blk */
if (!cur_drv->blk) {
    return;   /* refuse the data phase instead of dereferencing NULL */
}

Detection

Host ve telemetry sinyalleri

  • Process crash: QEMU SIGSEGV ile sonlanır; tek bir guest'le ilişkilenen QEMU binary'sinde bir segfault için host loglarını (journalctl, /var/log/libvirt/qemu/<domain>.log, dmesg) kontrol edin.
  • ASAN/debug build imzası: FDC data path'i içinde bir NULL (address 0x0 / küçük offset) read ya da write (fdctrl_read_data / fdctrl_write_data -> block backend access).
  • Anomaly: floppy media / floppy backend yapılandırılmamış bir VM'de FDC ioport aktivitesi (data read'leri izleyen DOR yazmaları) yapan bir guest şüphelidir — meşru guest'ler boş bir FDC'yi nadiren dürter.
  • Fleet pattern: tek bir tenant'a atfedilebilir tekrarlanan, kısa ömürlü QEMU restart'ları, host instability'den ziyade guest-triggered bir DoS'a işaret eder.

Mitigation

Remediation

  • Patch: "fdc: check drive block device before usage (CVE-2021-20196)" fix'ini içeren bir QEMU build'ine ya da onu shipleyen bir distro paketine (örn. Red Hat / Ubuntu / SUSE backport'ları) yükseltin.
  • Reduce attack surface: ihtiyacı olmayan guest'lere bir floppy controller attach etmeyin (-nodefaults ve -device floppy/fdc'yi atlayın); mevcut olmayan bir device dürtülemez.
  • Defense in depth: QEMU'yu azaltılmış ayrıcalıklarla ve confinement ile (dedike UID, -sandbox on üzerinden seccomp, SELinux/AppArmor svirt profilleri) çalıştırın ki bir crash sınırlı kalsın ve atfedilmesi kolay olsun.
  • Availability hardening: QEMU/libvirt'i denetleyin ki crash olan bir instance restart edilsin ve uyarı versin, bir DoS girişiminin etkisini sınırlayarak.

References