Skip to content

JavaScript Prime+Probe

Bir last-level-cache Prime+Probe side channel'ını, native kod olmadan ve physical adresleri bilmeden, tamamen bir web browser'daki sandbox'lı JavaScript'ten çalıştırmak.

Mechanism

Bu not vs. Prime+Probe

Bu not, jenerik Prime+Probe primitive'inin tarayıcıya özgü bir uygulamasıdır: native timer, clflush ve physical adres erişimi olmadan, sandbox'lı JavaScript'ten. Asıl yenilik attack döngüsü değil, browser kısıtları altında bunu mümkün kılan timer reconstruction (SharedArrayBuffer counting thread) ve COOP/COEP + Site Isolation mitigation'larıdır.

Neden çalışır

Prime+Probe'un victim ile memory paylaşmasına gerek yoktur — yalnızca aynı cache set'leri için contend etmesi gerekir. Last-level cache (LLC) physically indexed'dir ve tüm core'lar arasında paylaşılır, dolayısıyla belirli bir set'e map'lenen memory'ye dokunan herhangi bir kod o set'in line'ları için rekabet eder. JavaScript physical adresleri göremez veya clflush yayınlayamaz, ama buna gerek de yoktur: büyük bir typed array (örn. bir ArrayBuffer) bitişik bir physical page aralığıyla desteklenir ve cache set'ini seçen virtual adresin düşük bit'leri bir page içinde korunur. Array'i doğru stride'da gezerek JS bir eviction set — bir cache set'ini topluca dolduran bir adres grubu — oluşturabilir ve sonra kendi erişimlerini zamanlayabilir. Bir victim (aynı host'taki başka bir process, user veya VM) prime ile probe arasında o set'e map'lenen memory'ye dokunursa, attacker'ın line'larından birini evict eder ve probe'daki yavaş re-access aktiviteyi açığa çıkarır. Tek katı gereksinim, bir LLC hit'ini bir DRAM miss'inden ayırt edecek kadar hassas bir timer'dır.

Walkthrough

Attack üç kavramsal aşamada ilerler: timer, eviction-set kurulumu ve prime/probe loop'u.

  1. High-resolution bir timer edin. Orijinal çalışma, o zamanlar sub-microsecond çözünürlük açan performance.now()'u kullandı. Bu paper'dan sonra browser'lar performance.now()'u kabalaştırdı ve jitter ekledi; araştırmacılar (ve Google'ın leaky.page'i) bir SharedArrayBuffer üzerinde sayan bir counting thread kullanarak ince timer'ları yeniden inşa etti.
// High-resolution timer via a counter incremented in a Web Worker.
// The main thread reads a shared counter as a clock proxy.
const sab = new SharedArrayBuffer(8);
const clock = new Uint32Array(sab);
// worker.js runs: while (true) counter[0]++;
function timeAccess(probe) {
  const t0 = Atomics.load(clock, 0);
  probe();                       // touch the address under test
  return Atomics.load(clock, 0) - t0;
}
  1. Physical adres olmadan bir LLC eviction set kur. Bir büyük buffer allocate et, sonra aynı set-index bit'lerini paylaşan offset'leri grupla. Page-offset bit'leri virtual ve physical adresler arasında aynı olduğundan, LLC way size kadar aralıklı adresler aynı set'e düşer.
const buf = new Uint8Array(LLC_SIZE * 2);   // larger than the LLC
// Collect addresses one set-stride apart until accessing them all
// reliably evicts a target line (test-and-grow the candidate set).
  1. Prime, yield, probe. Eviction set'in her line'ını oku (prime), victim'in çalışmasına izin ver, sonra yeniden oku ve zamanla. Yavaş bir probe, set'in evict edildiği anlamına gelir.
prime(evictionSet);            // fill the target set with our lines
busyWaitOrYield();             // give the victim time to run
const t = timeAccess(() => probe(evictionSet));
record(t > THRESHOLD ? "victim-active" : "idle");
Per-set occupancy trace'in örnek çıktısı

set 1492  probe=58   idle
set 1492  probe=61   idle
set 1492  probe=240  victim-active   <- eviction observed
set 1492  probe=233  victim-active
set 1492  probe=57   idle
Oren et al. bu tür trace'leri, cache occupancy desenlerinden mouse hareketini ve network aktivitesini çıkaran sistem genelinde bir activity logger inşa etmek için kullandı.

Uyarılar

Teknik tek başına keyfi secret'ları değil, aktivite ve occupancy'yi çıkarır; belirli data'yı recover etmek, bilinen, cache-observable bir memory-access desenine sahip bir victim gerektirir. Modern browser'lar bu attack'in dayandığı timing primitive'lerini kaldırdı veya bozdu — bkz. Mitigation.

Detection

  • Bir SharedArrayBuffer üzerinde sıkı counting loop'ları yapan worker thread'leri başlatan sayfalara dikkat et (timer reconstruction'ın bir alameti).
  • Host'taki hardware performance counter'lar (LLC miss'leri, cache reference'ları) anomalous, yapılandırılmış eviction desenleri gösterir; cache attack'leri için genel olarak HPC tabanlı detector'lar önerilmiştir.
  • Browser telemetry: arka plandaki bir tab'da sürekli yüksek CPU ile LLC'ye yakın boyutlandırılmış büyük ArrayBuffer allocation'larının birleşimi yumuşak bir sinyaldir.

Mitigation

  • Timer'ı kaldır. Browser'lar performance.now() çözünürlüğünü kabalaştırdı ve jitter ekledi, ayrıca SharedArrayBuffer'ı (counting-thread timer'larının temeli) cross-origin isolation (COOP + COEP) arkasına kapattı.
  • Site Isolation, cross-site document'ları ayrı process'lere koyar; kötü niyetli bir sayfanın hassas içerikle paylaştığını azaltır ve Google'ın leaky.page Spectre PoC'siyle birlikte konuşlandırdığı çekirdek mitigation'dır.
  • Sunucu operatörleri, isolation'a opt-in yapmak ve data'larının bu tür sayfalara maruziyetini azaltmak için Cross-Origin-Opener-Policy: same-origin ve Cross-Origin-Embedder-Policy: require-corp gönderebilir.
  • Hardware/OS cache partitioning (örn. Intel CAT), cross-domain eviction'ı sınırlar ama genel olarak browser sandbox'larına açık değildir.

References