Spectre-PHT same-address-space in-place¶
Klasik Spectre v1 bounds-check bypass'ı: attacker ve victim aynı process'tir; attacker tam olarak victim branch'ini in-bounds input'larla eğitir, sonra tek bir out-of-bounds input verir ki conditional kendi bounds check'inin ötesine speculate etsin.
Mechanism¶
Note
Conditional branch'ler, branch address ve global branch history ile index'lenen saturating counter'lardan oluşan bir Pattern History Table (PHT) olan directional predictor tarafından predict edilir. Canella et al. transient-execution taksonomisinde bu variant Spectre-PHT, same-address-space, in-place (PHT-IP)'dir: mistraining branch'i ve victim branch'i aynı virtual address'teki bir ve aynı instruction'dır. O branch'i geçerli (in-bounds) input'larla tekrar tekrar execute etmek, PHT counter'ını "taken / check'i geç"e doğru sürükler. Attacker nihayet out-of-bounds bir index sağladığında, CPU bounds check'in hâlâ geçtiğini predict eder ve comparison retire olmadan önce guarded body'yi speculative olarak execute eder. Transient load secret-dependent memory'ye dokunur ve squash'tan sağ çıkan, Flush+Reload gibi bir covert channel üzerinden recover edilen bir microarchitectural iz (cached bir line) bırakır. Out-of-place kardeşinden (PHT-OP) temel fark: burada tam victim branch'in kendisi aynı virtual address'te eğitilir; PHT-OP'ta ise attacker, PHT index'inde victim'e alias'lanan farklı bir congruent shadow branch'i eğitir ve victim'i hiç çalıştırmaz — bkz. Spectre-PHT same-address-space out-of-place.
Walkthrough¶
Kocher et al.'den kanonik gadget — attacker x'i tümüyle kontrol eder:
// Victim gadget. array1_size, array1, array2 are shared with the attacker.
uint8_t array1[16]; // array1_size == 16
uint8_t array2[256 * 512]; // Flush+Reload probe array
void victim(size_t x) {
if (x < array1_size) // bounds check -- trained to "pass"
temp &= array2[array1[x] * 512]; // transient OOB read + encode
}
-
array2'nin 256 cache-line aralıklı slot'unu vearray1_size'ı flush et. -
In-place train et:
victim()'i geçerlix(0..array1_size-1) ile birçok kez çağır. Her çağrı aynı branch instruction'ı çalıştırır ve PHT counter'ını "taken / in-bounds"a doğru eğer. -
Trigger:
victim()'i,array1'in epey dışını gösteren (örn. bir secret'ın içine) malicious birxile çağır.array1_sizecache'ten evict edilmiş olduğundan, comparison yavaş resolve olur; PHT in-bounds predict eder ve CPUarray2[secret * 512]'yi speculative olarak hesaplar. -
Reload: her
array2slot'unu zamanla. Hızlı (cached) slot index'ii,secret = i'yi açığa çıkarır. Keyfi memory'yi dökmek için offset'ler boyunca tekrarla.
Beklenen davranış
Variant: Spectre-PHT, same-address-space, in-place (Spectre v1)
Trained: the exact victim branch, same virtual address
Mistrain: in-bounds inputs bias the branch's own PHT counter
Trigger: one out-of-bounds index -> speculative bounds-check bypass
Channel: Flush+Reload over array2 (cached slot == secret byte)
Result: read of memory the bounds check should have blocked
Detection¶
Doğrudan gözlemlemek zordur; bir victim gadget'ında yüksek branch-misprediction ya da Flush+Reload cache-miss oranları zayıf bir sinyal olabilir. Savunmalar detective değil preventive'dir.
Mitigation¶
Bounds check ile dependent load arasına bir speculation barrier (lfence) ya da
bir index mask ekle, böylece load predict edilen yolda ilerleyemez; data-dependent
array masking; JIT'lerde pointer/index sanitization. İndirect-branch kardeşi için
../mitigation/retpoline.md'a ve genel
Spectre genel bakışına bakın.