Skip to content

KPTI (Kernel Page-Table Isolation)

Userspace'e ayrı, neredeyse kernel'siz bir page table ver, böylece user mode'da çalışırken kernel'in belleği map'lenmemiş olur — Meltdown için production mitigation'ı.

Mechanism

Neden çalışır

Meltdown (CVE-2017-5754) transient execution'ı suistimal eder: bir kernel adresini okuyan bir user instruction fault verir, ama fault retire olmadan önce speculative load çoktan cache state'ini değiştirmiştir ve byte'ı bir Flush+Reload channel'ı üzerinden sızdırır. Bu çalışıyordu çünkü performans için kernel her process'in page table'larına map'leniyordu (yalnızca supervisor bit ile korunarak) — yani kernel adresi user mode'dan translate edilebilirdi, ki transient load'un ihtiyacı olan tek şey buydu.

KPTI/PTI önkoşulu ortadan kaldırır: process başına iki page-table seti tut ve user↔kernel sınırında CR3'ü switch et.

  • User page table'ları: userspace'i artı yalnızca kernel'e girip/çıkmak için gereken asgari kernel'i (entry/exit trampoline'leri, interrupt/IDT stub'ları, cpu_entry_area) map'ler. Kernel belleğinin büyük kısmı present değildir.
  • Kernel page table'ları: kernel'deyken kullanılan tam mapping.

Sırlar user execution sırasında basitçe unmapped olduğundan, Meltdown transient load'unun üzerinde speculate edeceği geçerli bir translation yoktur — sızdıracak bir şey yoktur. Geri kazanılan invariant: unmapped bellek (speculatively) okunamaz.

Walkthrough

KPTI bir kernel özelliğidir, yani "walkthrough" bir API çağırmak yerine onu işletmek ve gözlemlemektir.

1. PTI'nin aktif olup olmadığını kontrol et.

$ cat /sys/devices/system/cpu/vulnerabilities/meltdown
Mitigation: PTI

$ dmesg | grep -i 'page table isolation'
[    0.000000] Kernel/User page tables isolation: enabled

2. Toggle et (sahip olduğun bir kernel'de test için). PTI boot'ta kontrol edilir:

# disable (DANGEROUS - reopens Meltdown; test VMs only):
GRUB_CMDLINE_LINUX="... pti=off nopti"

# force enable:
GRUB_CMDLINE_LINUX="... pti=on"

3. CR3 switch'ini gör. Kernel entry/exit'te trampoline, CR3'ü iki PGD yarısı arasında swap eder. User/kernel PGD'leri order-1 (8 KB) bir çift olarak allocate edilir; CR3'ün bit 12'si (PTI_USER_PGTABLE_BIT) yarıyı seçer ve düşük bit'ler bir ASID/PCID encode eder, böylece switch tüm TLB'yi flush etmek zorunda kalmaz:

# entry_SYSCALL_64 trampoline (conceptually):
SWITCH_TO_KERNEL_CR3   # CR3 &= ~PTI_USER_PGTABLE_MASK  -> full kernel map
... handle syscall ...
SWITCH_TO_USER_CR3     # CR3 |=  PTI_USER_PGTABLE_MASK  -> restricted user map
sysretq

4. Maliyeti ölç. Her syscall/interrupt artık ~2 CR3 write'ı (~yüzlerce cycle) öder ve bir miktar global-page TLB verimliliği kaybeder:

$ perf bench syscall basic           # PTI on vs pti=off
# expect a measurable per-syscall regression (workload dependent),
# largest for syscall-heavy loads; PCID/ASID support softens it.

KPTI ≠ KASLR, ve Spectre değildir

KPTI, kernel belleğini unmap ederek Meltdown'ı yener; yan etki olarak bazı entry-trampoline leak'lerine karşı KASLR'yi de güçlendirir. Kurbanın kendi address space'i içinde sızdıran Spectre-v1/v2'yi durdurmaz.

Detection

Bir saldırı değil; gözlemlenebilirlik operasyoneldir: meltdown vulnerabilities dosyası, boot log satırı ve CONFIG_PAGE_TABLE_ISOLATION=y durumu gösterir.

Mitigation

(Bypass / residual risk.) KPTI yalnızca Meltdown'ı ele alır. İlgili transient saldırılar kendi düzeltmelerini gerektirir — örn. Spectre-v2 için retpoline/IBRS/eIBRS ve bazı CPU'larda entry/exit path'i L1TF/MDS için bir hedef olmaya devam eder; bunlar PTI yerine L1D flush ve core scheduling ile mitige edilir.

References