Skip to content

Linux KVM kvm_inject_page_fault info leak (CVE-2019-7222)

KVM, memory operand'ı bir MMIO adresine çözülen bazı VMX instruction'larını emulate ettiğinde, initialize edilmemiş bir exception structure taşıyan bir page fault inject eder ve host kernel stack içeriğini CR2 ile page-fault error code üzerinden guest'e leak eder.

Mechanism

Note

Bir page fault'ta KVM bir struct x86_exception doldurur (faulting address → CR2, artı bir error code) ve kvm_inject_page_fault() aracılığıyla onu guest'e inject eder. Kırılan invariant: bazı emulation path'leri, exception structure tam initialize edilmemişken injection helper'ını çağırıyordu. Guest-virtual-to-physical read helper'ları, bir MMIO operand'ı için exception field'larını sıfırlamadan bir error dönebiliyordu, böylece artakalan initialize edilmemiş kernel stack byte'ları inject edilen CR2 ve error code'a akıyordu — guest'in okuyabildiği değerler.

Bu bir uninitialized-stack-variable-infoleak'tir: doğrudan bir memory-corruption primitive'i değil, host stack memory'sine guest'in okuyabildiği bir side channel; KASLR'ı zayıflatır ve ileri exploitation'a yardımcı olur.

Walkthrough

Upstream patch'ten kavramsal reprodüksiyon ("KVM: x86: work around leak of uninitialized stack contents (CVE-2019-7222)", Paolo Bonzini; Felix Wilhelm tarafından raporlandı):

  1. Guest, bir memory operand'ı olan emulated bir VMX instruction'ı çalıştırır — VMXON, VMCLEAR, VMPTRLD, VMWRITE (memory form), INVEPT ya da INVVPID.
  2. Operand pointer'ı, sıradan RAM yerine bir MMIO adresine çözülür.
  3. KVM'in guest-memory read helper'ı MMIO operand'ında fail eder ve caller, hiç temizlenmemiş bir exception struct ile "körlemesine" kvm_inject_page_fault() çağırır.
  4. Inject edilen fault'un CR2 ve error code'u bu yüzden initialize edilmemiş host kernel stack byte'ları içerir; guest bunları fault'tan sonra okur.

Warning

Leak tekrarlanabilir ve guest-driven'dır; bir saldırgan faulting sequence'ı script'ler ve birçok stack word toplayarak zamanla host kernel address randomization'ını yener.

Fix shape (conceptual)

Yalnızca deterministik değerler guest'e ulaşsın diye exception'ı kullanmadan önce sıfırla:

memset(exception, 0, sizeof(*exception));
Patch, ideal fix'in handle_emulation_failureKVM_EXIT_INTERNAL_ERROR üzerinden userspace'e abort etmek olduğunu not eder, ama caller'lar buna hazır değildi, yani sıfırlamak pragmatik geçici workaround'dur.

Detection

  • Host'tan doğrudan gözlemlemek zordur (crash yok); sinyal, untrusted guest çalıştıran host'larda kernel sürümünü CVE-2019-7222 fix'ine karşı kontrol etmektir.
  • Guest tarafı/araştırma telemetrisi: CR2 değerleri guest'in kendi operand adresinden ziyade kernel-range pointer'lara benzeyen tekrarlanan emulated-VMX fault'ları.
  • Exception structure'ı initialize etmeden fault inject eden KVM nested-VMX emulation path'leri için audit yap.

Mitigation

  • Injection'dan önce exception field'larını sıfırlayan upstream fix'i / vendor backport'larını uygula (Şubat 2019'da shiplendi; 4.20.5'e kadar olan kernel'leri etkiledi).
  • Host kernel'lerini patch'li tut; fix küçük ve düşük riskli.
  • Defense in depth: kullanılmadığı yerde nested virtualization'ı devre dışı bırakmak, emulated-VMX attack surface'inin çoğunu kaldırır.

Ayrıca bkz. linux-kvm-nested-vmx-l2-to-l1-emulation-leak ve uninitialized-stack-variable-infoleak.

References