Skip to content

AMD L1D Way Predictor Reverse Engineering

AMD'nin bir adresin hangi L1D way'inde tutulduğunu tahmin etmek için kullandığı belgelenmemiş µTag hash'ini recover et; bu, güç tasarrufu sağlayan predictor'ı bir side channel'a (Collide+Probe / Load+Reload) dönüştürür.

Mechanism

Neden çalışır

Güç tasarrufu için, AMD'nin L1D cache'i (Bulldozer'dan Zen 2'ye kadar) tüm way'leri paralel olarak probe etmez. Küçük bir way predictor, virtual adresi 8-bit'lik bir µTag'e hash eder ve tek bir predicted way'i lookup etmek için bunu kullanır; böylece bir load'da yalnızca o way enerjilenir.

Attacker'ın istismar ettiği invariant: aynı µTag'e sahip iki farklı virtual adres bir collision olarak ele alınır. İkinci adrese erişildiğinde predictor yanlış tahmin eder (mispredict), load doğru way'e karşı replay edilir ve erişim ölçülebilir derecede daha yavaş olur. Yalnızca 256 µTag olduğundan, bir attacker bir kurban'ınkiyle collide olan bir virtual adresi ucuza bulabilir, ardından bu collision'ın timing'ini kullanarak kurban'ı izleyebilir — hiçbir shared memory ve physical adres bilgisi olmadan.

µTag, virtual-address bit'lerinin linear (XOR-based) bir fonksiyonudur. Bit 0–5 line offset'tir ve bit 6–11 L1D set'ini seçer; µTag hash'ini yalnızca bit 12–27 besler. Linearity, 8 output bit'inin her birinin bu bit'lerin sabit bir alt kümesinin sadece bir XOR'u olduğu anlamına gelir; yani tüm fonksiyon çözülebilir.

Flush+Reload ile karşılaştırın: Load+Reload benzer bir same-core trace verir ama Flush+Reload'un aksine line'ı invalidate etmez (clflush yok), bu yüzden hiç LLC eviction tetiklemez ve daha gizlidir (stealthier).

Walkthrough

1. Bir µTag-collision timing primitive'i kur. a adresine eriş, ardından bir aday b'ye eriş; eğer b, a'nın µTag'ini paylaşıyorsa predictor mispredict eder ve ikinci erişim yavaş olur.

// rdtscp-timed access; a and b are distinct virtual addresses.
static inline uint64_t probe(void *a, void *b) {
    maccess(a);                 // train predictor with a's way for its µTag
    uint64_t t = time_load(b);  // if µTag(b)==µTag(a): misprediction -> slow
    return t;
}

2. Hash'i reverse-engineer et. Tüm aday adresleri tek bir L1D set'inde tut (bit 6–11 sabit), her seferinde 12–27 aralığında bir bit flip'le ve hangi flip'lerin collision sonucunu çevirdiğini kaydet. Her µTag output bit'i bir linear denklem haline gelir:

a_27 x_27 ⊕ a_26 x_26 ⊕ ... ⊕ a_12 x_12 = y_s

Sistemi çözmek XOR set'lerini recover eder. Zen / Zen+ üzerinde recover edilen fonksiyon şudur:

Recovered µTag hash (Zen / Zen+, from the paper)
h(v):  each output bit b0..b7 is an XOR of two virtual-address bits
       from the v12..v27 range (spacing is irregular), e.g.
  b0 = v12 ⊕ v27
  b1 = v13 ⊕ v22
  b2 = v14 ⊕ v21
  b3 = v15 ⊕ v20
  b4 = v16 ⊕ v19
  b5 = v17 ⊕ v18
  b6 = v18 ⊕ v23
  b7 = v19 ⊕ v24
(Zen 2 splits each 4 kB page into two halves, doubling the µTags.)

3. Collide+Probe — shared memory olmadan logical core'u paylaşan bir kurban'ı izle: µTag'i hedefinkine eşit olan bir attacker adresi seç, onu prime et, kurban'ın çalışmasına izin ver, ardından yeniden time'la. Yavaş bir erişim, kurban'ın collide olan bir adrese eriştiği anlamına gelir.

$ ./collide_probe --victim-utag 0x5a
chosen attacker VA 0x7f3c12000 : µTag 0x5a   (collision)
idle round:   reload =  47 cycles  (no victim access)
victim round: reload = 112 cycles  (victim touched colliding line)

4. Load+Reload — aynı physical core, shared (read-only) memory: shared line'ı load et, kurban'ın çalışmasına izin ver, onu reload et. Way predictor, kurban'ın erişimini line'ı evict etmeden misprediction penalty üzerinden açığa çıkarır.

Noise and microarch coverage

Yalnızca bir way predict edilir; bu yüzden SMT sibling'ler, prefetcher'lar ve replacement policy gürültü (noise) ekler — thread'leri pin'le ve prefetcher'ları devre dışı bırak. Kesin µTag fonksiyonu Zen jenerasyonları arasında farklılık gösterir; yayınlanmış formülü varsaymak yerine bit-flip recovery'sini hedef CPU üzerinde yeniden çalıştır.

Mitigation

  • AMD'nin yönergesi: way-prediction davranışı chicken bit'leri / microcode ile kontrol edilir; sonraki core'lar predictor'ı devre dışı bırakabilir veya randomize edebilir.
  • Genel Spectre sınıfı hijyen (KPTI tarzı isolation, shared page'lerde secret-dependent VA'lar bulundurmamak) channel'ın gözlemleyebileceğini sınırlar.

References