Skip to content

QEMU LSI53C895A SCSI infinite loop (CVE-2019-12068)

Hazırlanmış bir SCSI script'i, emüle LSI53C895A controller'ını sonlanmayan bir execution loop'una sürebilir, bir host CPU'sunu meşgul edip QEMU'yu askıya alabilir (guest-to-host DoS).

Mechanism

Bug sınıfı: sınırsız guest-driven interpreter loop'u (ilerleme/sonlanma sınırı yok)

LSI53C895A, scriptable bir SCSI controller'dır: guest memory'ye küçük bir "SCRIPTS" programı yerleştirir ve device onu çalıştırır. QEMU bunu lsi_execute_script()'te emüle eder; bu, script pointer'ı s->dsp'deki opcode'u fetch eden, üzerinde işlem yapan ve s->dsp'yi bir sonraki instruction'a ilerleten bir döngüdür.

Interpreter'ın zorlaması gereken invariant, invocation başına sınırlı toplam maliyetle ileri ilerlemedir. Orijinal döngü yalnızca belirli instruction sonuçlarında sonlanırdı; no-op / boş opcode'lar döngüyü güvenilir şekilde kırmadı ya da herhangi bir limite doğru sayılmadı. Bir guest, interpreter'ın ne anlamlı ilerleme kaydeden ne de bir çıkış koşuluna ulaşan opcode'ları fetch etmeye devam edeceği bir script hazırlayabilir (ya da memory ayarlayabilir).

Tüm döngü QEMU vCPU/IO thread'i içinde senkron çalıştığı için, sonlanmayan bir script kontrolü asla bırakmaz: bir host CPU'su %100'de döner ve VM (ve o QEMU thread'i) yanıt vermez hale gelir. Sınır aşılır çünkü guest, host'un körü körüne yorumladığı programı tamamen yazar ve host meşru bir script'in eninde sonunda sonlandığına güvendi.

Walkthrough

Upstream patch serisine dayalı kavramsal reproduction.

  1. Guest, LSI controller'ı, instruction stream'i sonlandırıcı bir opcode'a yakınsamayan bir SCRIPTS programını çalıştıracak şekilde programlar (örn. eski döngünün ne sınırladığı ne de üzerinde çıktığı bir no-op/boş opcode dizisi).

  2. Guest, script execution'ı başlatır; QEMU lsi_execute_script()'e girer.

Conceptual loop shape (logical fragments, not an exploit)
# Emulator side (paraphrased, pre-fix):
while (true) {
    insn = fetch_opcode(s->dsp);   # read next SCRIPTS opcode
    dispatch(insn);                # some opcodes don't terminate the run
    s->dsp = next(s->dsp);         # advance pointer
    # ...no per-invocation instruction cap -> can spin forever
}
  1. Bir çıkış koşuluna asla ulaşmayan bir opcode stream'iyle döngü süresiz çalışır; host thread'i takılır ve VM askıya alınır.

Corruption değil, DoS

Bu saf bir availability bug'ıdır: burada bir memory write primitive'i yoktur. Hasar, sıkışmış bir host thread'i / CPU tükenmesidir; bu, paylaşılan host'larda co-tenant VM'leri bozabilir.

Fix, interpreter'ı sınırlar: bir instruction count limit'i (LSI_MAX_INSN, 10000) tanıtır ve o kadar instruction — no-op'lar dahil — çalıştırıldığında döngüden çıkar, bir illegal-instruction interrupt'ı (LSI_DSTAT_IID) yükseltir, disconnect eder ve script'i durdurur:

/* Conceptual shape of the upstream fix (paraphrased) */
if (insn_processed++ > LSI_MAX_INSN) {   /* LSI_MAX_INSN == 10000 */
    /* treat as illegal: raise DSTAT.IID, disconnect, stop running */
    lsi_script_dma_interrupt(s, LSI_DSTAT_IID);
    break;
}

Detection

Host ve telemetry sinyalleri

  • CPU pinning: I/O ilerlemesi olmadan ~%100 CPU'da takılı bir QEMU thread'i; host'taki perf top / bir profiler, zamanın lsi_execute_script ve dispatch helper'larında yoğunlaştığını gösterir.
  • Guest hang: QEMU process'i canlı kalırken etkilenen VM yanıt vermeyi durdurur (bunu crash tarzı DoS CVE'lerinden ayırır).
  • Anomaly: büyük/döngüsel LSI SCRIPTS aktivitesi ya da idle olması gereken device'lardan LSI DMA çıkaran bir guest şüphelidir.
  • Watchdog: tek bir tenant'la ilişkilenen host seviyesindeki "VM yanıt vermiyor ama process çalışıyor" uyarıları, guest-driven bir spin loop'una işaret eder.

Mitigation

Remediation

  • Patch: "scsi: lsi: exit infinite loop while executing script (CVE-2019-12068)" fix'ine (LSI_MAX_INSN cap) sahip bir QEMU build'ine ya da bir distro backport'una (Oracle/EulerOS ve diğerleri gönderdi) yükseltin.
  • Reduce attack surface: legacy lsi53c895a controller'ı yerine virtio-scsi/virtio-blk'i tercih edin; LSI modelini ihtiyacı olmayan guest'lere expose etmeyin.
  • Resource isolation: QEMU CPU'sunu cgroup'larla (cpu.max) pin'leyin/sınırlayın ki dönen bir thread co-located workload'ları aç bırakamasın; hung-VM koşulları için denetleyin ve restart edin.
  • Confinement: etkiyi sorunlu instance'a sınırlamak için standart svirt/seccomp sertleştirmesi.

References