Linux KVM SEV-ES VMGEXIT string-IO OOB (CVE-2021-4093)¶
CVE-2021-4093: bir SEV-ES guest, count/size'ı tek sayfalık
pio_databuffer'ını aşan bir string I/O instruction'ı (ins/outs, exit reasonSVM_EXIT_IOIO) için bir VMGEXIT oluşturabilir ve L0 host kernel'inde bir out-of-bounds read/write sürebilir.
Mechanism¶
Bug class: guest-controlled uzunluk vs. sabit boyutlu bir host I/O buffer'ı
Risk altındaki boundary encrypted SEV-ES guest -> L0 host kernel'dir. SEV-ES ile
guest register state'i encrypted'tır, dolayısıyla guest emulated-instruction
verisini host'a açıkça GHCB üzerinden bir VMGEXIT ile vermek zorundadır. String
port I/O için, KVM veriyi guest GHCB buffer'ı ile per-vCPU vcpu->arch.pio_data
buffer'ı arasında kopyalar.
Kırılan invariant: pio_data bir sayfadır, ama string-I/O emulation'ı transfer
size'ını guest-controlled repeat count ve access size'tan, o sayfaya karşı
bound'lamadan türetiyordu. Aşırı boyutlu bir count advertise eden malicious bir
VMGEXIT bu yüzden host memcpy'ının buffer'ı aşmasına neden olur — host tarafı bir
out-of-bounds-write (ve read). Sıradan I/O
emulation'ının aksine, SEV-ES bunu tamamen guest-supplied GHCB üzerinden yönlendirir,
yani parametreleri tamamen guest kontrol eder.
Corruption pio_data'ya komşu kernel allocation'larına düştüğünden, dökümante edilmiş
en kötü durum host crash'inden potansiyel bir guest-to-host escape'e doğru tırmanır.
Bkz.
severity-code-injection-attacks-against-encrypted-vms.
Walkthrough¶
Public Red Hat Bugzilla'sından ve upstream SEV-ES string-I/O fix serisinden çıkarılan yüksek seviyeli reprodüksiyon şekli (AMD host, SEV-ES guest):
- Bir SEV-ES guest, bir string I/O instruction'ı (
ins/outs) çalıştırır veSVM_EXIT_IOIOüzerinden exit eder, operasyonu bir VMGEXIT'te GHCB üzerinden sağlar. - Guest, bir sayfadan büyük bir repeat count / access size advertise eder.
- Host string-I/O handler'ı (
kvm_sev_es_string_io/sev_es_string_io), o kadar byte'ı tek sayfalıkpio_databuffer'ına/buffer'ından kopyalar. - Bound'lanmamış
memcpy,pio_data'nın ötesini okur/yazar ve komşu host kernel memory'sini corrupt eder.
Fix her transfer'ı buffer'a bound'lar ve GHCB verisi daha büyük olduğunda, onu tek bir aşırı boyutlu kopya yerine birden çok sayfa boyutlu pass'te işler.
Fix'in temsili şekli (arch/x86/kvm/svm/sev.c)
Örnekleyici fragment
Multi-pass fix niyetinin kavramsal temsili, birebir kopya değil. Tam kod için atıf yapılan Red Hat Bugzilla / upstream commit'lerine bak.
Detection¶
- SEV-ES guest'leri çalıştıran AMD host'ları: backtrace'i SVM string-I/O /
SVM_EXIT_IOIOhandling'inden geçen KASAN out-of-bounds splat'ları ya da host oops'ları için dikkatli ol. - Çok büyük repeat count'lu anormal VMGEXIT string-I/O istekleri tetikleyici sinyaldir; mümkün olduğu yerde GHCB-driven I/O size'larını instrument et/sınırla.
- Port I/O tetikleyen spesifik bir confidential-computing tenant'ıyla ilintili crash'ler.
- Bu OOB class'ını exploitation öncesi yüzeye çıkarmak için debug/canary host'larını KASAN ile çalıştır.
Mitigation¶
- SEV-ES string-I/O hardening serisinde upstream düzeltildi (Linux 5.15; 5.14.16'ya backport edildi). Dağıtımının patch'li kernel'ini uygula (Red Hat Bugzilla 2028584 fix'leri izler; Ubuntu update'ler shipledi).
- Patch'lenene kadar hangi tenant'ların SEV-ES guest çalıştırabileceğini kısıtla; surface yalnızca SEV-ES VM'leri için var.
/dev/kvmerişimini trusted workload'larla sınırlı tut.