Nested virtualization (L0/L1/L2 trap-and-emulate)¶
Gerçek host'un (L0), guest hypervisor'ın (L1) privileged virtualization instruction'larını trap edip emulate etmesini sağlayarak bir VM içinde bir hypervisor çalıştırma; böylece L1, mimari olarak yalnızca tek seviye VMX/SVM destekleyen bir CPU üzerinde kendi guest'ini (L2) çalıştırabilir.
Mechanism¶
Note
x86 hardware virtualization (Intel VT-x / AMD-V) tek seviye için inşa edilmiştir: non-root guest'ler çalıştıran bir root-mode hypervisor. Native bir ikinci seviye yoktur — dolayısıyla bir guest içinde hypervisor çalıştırmak için L0, tek donanım virtualization katmanını L1 ve L1'in tüm L2 guest'leri arasında multiplex etmek zorundadır ("Turtles" modeli).
Temel hile trap-and-emulate'dir. L1 donanıma sahip olduğuna inanır ve VMX/SVM
instruction'larını çalıştırır (VMXON, VMPTRLD, VMREAD, VMWRITE,
VMLAUNCH/VMRESUME ya da VMRUN). Bu instruction'lar L0'a VM-exit eder. L0, L1
için gerçek bir donanım VMCS'i (VMCS01) tutar; L1, L2 için donanımın asla
görmediği bir software VMCS'i (VMCS12) kurar; ve L0 ikisini, CPU'nun L2'yi
çalıştırmak için kullandığı gerçek yapı olan VMCS02'ye merge eder. Memory de
nested EPT üzerinden aynı şekilde ele alınır (shadow EPT02 =
EPT12 ∘ EPT01). L0'ın zorunlu kılması gereken invariant: L1 ve L2 yalnızca L0'ın
fiilen verdiği privilege'lere sahip olur — L0, donanıma ulaşmadan önce L1'in
sağladığı her control/state field'ını yeniden validate eder, çünkü bir guest
hypervisor untrusted input'tur. KVM, Linux v4.20'den beri nested VMX'i varsayılan
olarak etkinleştirir.
Walkthrough¶
Public reference: Turtles (OSDI 2010) ve KVM nested-VMX docs. Tek bir L2 entry'sinin kavramsal yaşam döngüsü:
- L1
VMLAUNCH/VMRESUME(Intel) ya daVMRUN(AMD) çalıştırır -> L0'a VM-exit. - L0, L1'in VMCS12'sini (ya da VMCB12'sini) okur, her control/guest-state field'ını validate eder ve geçerli field'ları VMCS02'ye merge eder (ve shadow EPT02'yi kurar).
- L0, VMCS02 kullanarak L2'yi gerçek donanımla çalıştırır.
- Bir L2 exit'inde L0, onu L1'in mi ele alması gerektiğine (VMCS12'yi güncelleyerek exit'i L1'e yukarı reflect ederek) yoksa L0'ın doğrudan mı ele alacağına karar verir.
- Tekrarla; performance için yalnızca dirty field'lar yeniden kopyalanır (bu optimizasyon enlightened VMCS / VMCS shadowing tarafından formelleştirilmiştir).
Beklenen gözlemlenebilir: L1 işleyen bir hypervisor olarak çalışır; VMX/SVM instruction'ları donanıma doğrudan dokunmak yerine sessizce L0'a trap eder.
Warning
L1'in sağladığı her VMCS/VMCB field'ı L0'ın bakış açısından attacker-controlled'dur. Validation'ı atlamak (ya da validation'dan sonra onu yeniden okumak — bir double-fetch), L2-to-L1 ve guest-to-host escape'leri mümkün kılan klasik nested-virt bug sınıfıdır.
Sibling not
Bu not nesting'in bütünsel mimarisini (L0/L1/L2 trap-and-emulate, Turtles modeli, memory dahil) anlatır. VMCS01/02/12 merge'ünün structure-level detayı ve field-merge bug class'ı ayrı bir not'tadır: VMCS multiplexing for nesting.
Walkthrough — enabling/observing (host)¶
# Intel: confirm nested VMX is on
cat /sys/module/kvm_intel/parameters/nested # expect Y / 1
# AMD:
cat /sys/module/kvm_amd/parameters/nested # expect Y / 1
Nesting açıkken, bir L1 guest'i kvm_intel/kvm_amd'yi load edip kendi L2'sini boot edebilir.
Detection¶
- L0 tarafı: nested-virt aktivitesi, L1'den gelen VMX/SVM-instruction VM-exit'leri ve VMCS12/VMCS02 yönetimi olarak görünürdür; anormal oranlar ya da consistency check'lerde başarısız olan field'lar düşmanca bir L1'i işaret eder.
Mitigation¶
- L1'in sağladığı tüm control structure'ları her entry'de validate et; bir kez güvenilir bir buffer'a kopyala (double-fetch yok).
- Host kernel'i nested-virt CVE'leri için patch'li tut.
- Gerekmediği yerde nesting'i devre dışı bırak (
kvm_intel.nested=0/kvm_amd.nested=0).
References¶
- "The Turtles Project: Design and Implementation of Nested Virtualization" (OSDI 2010). https://www.cs.utexas.edu/~witchel/380L/papers/benyehuda10osdi-turtles.pdf
- "Nested VMX" — KVM x86 documentation. https://docs.kernel.org/virt/kvm/x86/nested-vmx.html