Skip to content

Linux KVM INVPCID CR0.PG=0 NULL deref (CVE-2022-1789)

Shadow paging aktifken, paging devre dışıyken (CR0.PG=0) INVPCID çalıştıran bir guest, hiç install edilmemiş bir MMU invlpg callback'ine ulaşır, böylece KVM bir NULL function pointer'ı dereference eder ve host'u crash eder (guest-to-host denial of service).

Mechanism

Note

KVM, guest MMU'yu, davranışı aktif paging mode'a göre kurulan function-pointer callback'ler (örneğin invlpg) üzerinden dispatch edilen bir struct kvm_mmu olarak modeller. Kodun dayandığı invariant, kvm_mmu_invpcid_gva()'ya yalnızca invlpg callback'i dolu olan bir MMU ile ulaşılmasıydı. Guest, shadow paging altında CR0.PG=0 ile INVPCID çalıştırdığında bu varsayım kırılır: o konfigürasyonda invlpg callback'i set edilmemiştir, ama INVPCID emulation path'i yine de onun üzerinden çağrı yapar ve host kernel context'inde bir NULL pointer'ı dereference eder.

Bu klasik bir missing-callback-guard bug'ıdır: handler'ın hiç atanmadığı bir mode'da ulaşılabilen bir code path üzerinde, per-mode bir handler koşulsuz invoke edilir. Unprivileged bir guest'ten ulaşılabilen bir null-pointer-dereference'tır ve bir privilege escalation yerine bir host crash'i verir.

Walkthrough

Upstream fix'ten kavramsal reprodüksiyon (commit 9f46c187e2e6, "KVM: x86/mmu: fix NULL pointer dereference on guest INVPCID", Paolo Bonzini):

  1. Host, guest'i shadow paging ile çalıştırır (bu MMU rolü için EPT/NPT kullanımda değil).
  2. Guest paging'i devre dışı bırakır (CR0.PG = 0) ve bir INVPCID instruction'ı issue eder.
  3. KVM INVPCID'yi emulate eder ve verilen guest-virtual mapping'i current ve previous root'lar boyunca invalidate etmek için kvm_mmu_invpcid_gva() çağırır.
  4. O helper mmu->invlpg(...)'yi invoke eder, ama CR0.PG=0 ile invlpg callback'i hiç install edilmemiştir → NULL function-pointer çağrısı → host oops.

Warning

Trigger tamamen guest-controlled'dır ve guest içinde, paging kapalıyken INVPCID çalıştırmanın ötesinde özel bir privilege gerektirmez — hostile ya da buggy bir VM'den az çabalı bir host DoS'u.

Fix shape (conceptual)

Her callback kullanımını guard et:

if (mmu->invlpg)
    mmu->invlpg(vcpu, gva, mmu->root.hpa);
CR0.PG / EFER.LMA mode kontrolleri eklemek yerine, hem aktif PCID için hem de previous root'ları walk ederken uygulanır.

Detection

  • kvm_mmu_invpcid_gva (ve INVPCID emulation path'i) üzerinden geçen bir NULL-deref backtrace'iyle birlikte host kernel oops / panic imzadır.
  • Crash'i spesifik bir guest'le ilintilendir: fault'tan kısa süre önce INVPCID issue etmiş, özellikle de CR0.PG'yi toggle'layan bir VM.
  • Host stability monitoring: untrusted ya da multi-tenant guest çalıştıran host'larda açıklanamayan KVM ilişkili panic'ler, kernel sürümünü patch'e karşı kontrol etmeyi gerektirir.

Mitigation

  • mmu->invlpg'yi çağırmadan önce guard eden upstream fix'i (commit 9f46c187e2e6) / vendor backport'larını uygula.
  • Host kernel'lerini güncel tut; dağıtımlar bunu 2022'de bir stable update olarak shipler.
  • Patch'leme geride kaldığında, host'ta untrusted guest kodunu kimin çalıştırabileceğini kısıtla, çünkü bug güvenilir bir guest-triggered host DoS'udur.

İlişkili bir guest-triggered NULL-deref pattern'i için ayrıca bkz. linux-kvm-synic-stimer-msr-null-deref, ve bug class'ı için null-pointer-dereference.

References