Skip to content

Flush+Flush

clflush instruction'ın kendi execution süresini ölç — uncached bir line'da daha hızlı, cached bir line'da daha yavaştır — böylece hiç memory access yapmadan victim'ın shared bir line'a dokunup dokunmadığını öğren.

Mechanism

Neden çalışır

clflush bir line'ı tüm cache hierarchy'sinden evict eder, ama kendi execution süresi line'ın o anda cached olup olmadığına bağlıdır: present olan bir line'ı flush'lamak, zaten absent olan birini flush'lamaktan daha uzun sürer (CPU onu seviyeler boyunca bulup invalidate etmek zorundadır). İşte bu timing farkı channel'ı oluşturur.

leak/transmit/decode invariant'ı — Flush+Reload'un daha stealthy bir kardeşi:

  • Leak: attacker seçtiği bir shared line'ı flush'lar ve flush'ı time'lar. Yavaş bir flush, line'ın cached olduğu anlamına gelir — yani victim onu bir önceki flush'tan beri access etmiştir; hızlı bir flush ise uncached olduğunu gösterir.
  • Transmit/decode: monitor edilen bir line üzerinde flush-and-time tekrarlamak, victim'ın access pattern'ini doğrudan clflush latency'sinden verir.

Asıl önemli özellik: Flush+Flush hiç memory access yapmaz. Attacker tarafında hiç cache miss üretmez ve cache hit'leri minimize eder, bu yüzden klasik hardware-performance-counter detector'lar (ki bir saldırının attacker'ın hit/miss'lerini şişirdiğini varsayarlar) onu göremez — daha hızlı ve daha stealthy'dir, bunun bedeli ise daha gürültülü, daha düşük çözünürlüklü bir sinyaldir.

Walkthrough

Tek primitive, time'lanmış bir clflush'tır:

// gcc -O2 -mclflushopt? no: plain clflush. x86-64.
#include <stdint.h>
#include <x86intrin.h>

static inline uint64_t flush_time(void *addr) {
    unsigned aux;
    uint64_t t0 = __rdtscp(&aux);
    _mm_clflush(addr);            // time the flush itself; no load!
    uint64_t t1 = __rdtscp(&aux);
    return t1 - t0;               // slow => line was cached (victim touched it)
}

Bir victim time slot'u ile flush-and-time loop'layarak bir shared line'ı monitor et:

char *target = shared_map + OFFSET;     // line the victim also maps
for (;;) {
    nanosleep(&slot, NULL);             // victim runs
    uint64_t t = flush_time(target);    // slow => victim accessed target
    if (t > THRESHOLD) record_hit();    // (also re-flushes for next round)
}

THRESHOLD'u cached ve uncached flush latency'leri arasındaki vadide kalibre et.

Beklenen flush-latency ayrımı (kavramsal)
flush of CACHED line   : ~180 cycles  (victim touched it)
flush of UNCACHED line : ~140 cycles
smaller gap than Flush+Reload -> noisier but stealthier

Detection

  • Flush+Reload'a göre tespit edilmesi daha zordur çünkü attacker çok az hit/miss üretir; detector'ların bu yüzden cache-miss sayıları yerine anormal derecede yüksek clflush execution oranlarını izlemesi gerekir.

Mitigation

  • Flush+Reload ile aynı yapısal savunmalar: cross-boundary page sharing'den kaçın (KSM/dedup'ı disable et), constant-time code kullan, clflush/high-res timer'ları kısıtla.

References