Skip to content

Page-fault injection into guest (fetch swapped-out pages)

Doğru address ve process context'inde guest'e bir #PF (vector 14) inject ederek bir guest OS'u, swap'lanmış bir page'i RAM'e geri getirmeye zorlama; böylece dış bir introspection engine, disk üzerinde olan ve aksi hâlde VM dışından okunamayan bir page'i okuyabilir.

Mechanism

Note

Memory introspection, guest page table'larını yürüyerek guest RAM'ini okur, ama hedef bir virtual page non-present (swap'lanmış) olabilir — physical memory'de okunacak hiçbir şey yoktur. Introspection katmanı OS bilgisi olmadan onu kendisi page-in edemez. Hile: gerçek bir erişimde guest'in alacağı tam fault'u synthesize ederek paging'i guest OS'a yaptırmak.

Hypervisor, hazırlanmış bir error code ve CR2 (faulting address) ile guest'e bir page fault (vector 14) iletmek için hardware event injection kullanır. Guest'in kendi page-fault handler'ı sonra page table'larını yürür, disk read'ini gönderir ve page'i install eder — bu noktada introspector onu okuyabilir. Sömürülen invariant: guest OS gördüğü herhangi bir mimari #PF'ye sadakatle hizmet eder, dolayısıyla hassas biçimde oluşturulmuş, inject edilmiş bir fault gerçek bir access fault'undan ayırt edilemez ve normal swap-in path'ini tetikler. Doğruluk context'e bağlıdır: #PF yalnızca hedef process current iken (CR3 eşleşirken) ve güvenli bir execution noktasında inject edilmelidir, aksi hâlde yanlış mapping'i çözer ya da guest'i crash eder.

Walkthrough

Public reference: Bitdefender HVMI, "Page Fault Injection in Virtual Machines." Swap'lanmış bir user page'i okumak için kavramsal akış:

  1. Hedef GVA'yı çöz; page-table walk yoluyla onun non-present (disk üzerinde) olduğunu keşfet.
  2. Sahip process schedule edilene kadar bekle (guest CR3 hedefle eşleşir).
  3. PF error code'unu oluştur (örn. user-mode, non-present bir erişim için 0x4 — bit 2

    "user", bit 0 temiz "non-present") ve VT-x event injection ile CR2 = target GVA olacak şekilde vector 14'ü inject et.
  4. Page'in tam olarak ne zaman resident olduğunu bilmek için ilgili page-table entry'lerini EPT-protect et: guest yeni physical address'i PTE'ye yazdığında bir EPT violation tetiklenir; yeni GPA'yı geri kazanmak için onu decode et.
  5. Artık resident olan page'i SLAT üzerinden oku.
Injection skeleton
if pte_non_present(target_gva) and current_cr3 == target_cr3:
    ept_write_hook(pte_levels(target_gva))   # detect swap-in
    inject_event(vector=14, error_code=0x4, cr2=target_gva)
    # on EPT-violation from PTE write -> extract GPA -> read page

Warning

Yalnızca doğru process context'inde ve fault mode'unda inject et. Yüksek IRQL'de kernel-mode bir #PF ya da yanlış CR3 için bir fault guest'i bug-check edebilir. PTE-write hook'u artı injection racy'dir ve dikkatle senkronize edilmelidir.

Detection

  • Guest içinden bu sıradan demand paging'e benzer ve ayırt etmesi zordur; anomaliler (process'in asla dokunmadığı address'ler için fault'lar ya da beklenmedik swap-in fırtınaları) tek davranışsal ipuçlarıdır.

Mitigation

  • Bu, introspection tool'ları tarafından meşru biçimde kullanılan hypervisor'ın bir capability'sidir; bir guest aşağıdan gelen fault injection'ı engelleyemez.
  • Confidential-computing memory protection'ı (encrypted/attested guest memory), dış bir tarafın page-in edilmiş veriyle yapabileceklerini kısıtlar.

References

  • Bitdefender HVMI — "Page Fault Injection in Virtual Machines: Accessing Swapped-Out Pages from HVMI." https://bitdefender.github.io/hvmi-blog/2020/12/14/pfinjection.html