Skip to content

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
}
  1. array2'nin 256 cache-line aralıklı slot'unu ve array1_sizeflush et.

  2. In-place train et: victim()'i geçerli x (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.

  3. Trigger: victim()'i, array1'in epey dışını gösteren (örn. bir secret'ın içine) malicious bir x ile çağır. array1_size cache'ten evict edilmiş olduğundan, comparison yavaş resolve olur; PHT in-bounds predict eder ve CPU array2[secret * 512]'yi speculative olarak hesaplar.

  4. Reload: her array2 slot'unu zamanla. Hızlı (cached) slot index'i i, 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.

References