An educational proof-of-concept (PoC) tool demonstrating Flush+Reload cache side-channel analysis on the AArch64 (ARM64) architecture.
This tool demonstrates how timing differences between CPU Cache and DRAM accesses can be measured at the user-space level (EL0) to infer memory access patterns. It features dynamic threshold calibration and incorporates a Fisher-Yates shuffle algorithm to mitigate the effects of aggressive hardware prefetchers.
- AArch64 Inline Assembly: Utilizes native ARM64 assembly instructions (
cntvct_el0for high-resolution system virtual counter reading anddc civacfor hardware-enforced cache line flushing). - Dynamic Calibration: Automatically measures and calculates the timing threshold separating L1/L2 Cache hits from DRAM accesses under the current system load.
- Prefetcher Bypass: Implements a non-linear Fisher-Yates index shuffling technique using a Galois LFSR pseudo-random number generator to prevent the hardware stride prefetcher from loading adjacent cache lines prematurely.
- Hybrid V and C Implementation: Written in the V programming language with performance-critical primitives offloaded to inline C functions.
The analysis runs in four distinct phases:
- Calibration: The tool repeatedly flushes a test memory address and measures DRAM latency, then accesses it again to measure cache latency. It establishes a dynamic decision threshold as the average of these two values.
- Flush Phase: The monitored buffer is entirely evicted from the cache hierarchy using the
dc civacinstruction. - Victim Access (Simulation): The "victim" accesses a specific memory offset corresponding to the
secret_byte(e.g.,85 * page_size), bringing that specific cache line back into the cache. - Reload Phase: The tool probes all 256 possible offsets. To bypass hardware prefetchers, the probing order is fully randomized using a shuffled index array. If the access latency for an offset falls below the calibrated threshold, it is registered as a cache hit.
- Statistical Analysis: The byte index with the highest registered cache hits is determined to be the recovered secret.
- An AArch64 hardware platform (e.g., Raspberry Pi 4/5, Pine64, ARM64 Android device, or Apple Silicon/ARM64 servers).
- User-space access to the virtual counter (
cntvct_el0) and cache maintenance instructions (dc civac). Note: On some Linux kernel configurations, EL0 access to these instructions might be restricted. - The V Compiler (Vlang) installed.
- GCC or Clang configured for AArch64 compilation.
Compile the program using the V compiler with GCC as the backend:
v -cc gcc ramoops.vRun the compiled executable:
./ramoopsThe high-resolution timing is achieved by isolating memory reads using Instruction Barrier (isb) instructions to prevent out-of-order execution from distorting the results:
__asm__ volatile(
"isb\n\t"
"mrs %0, cntvct_el0\n\t"
"isb"
: "=r" (t0)
:
: "memory"
);Cache line eviction uses the Data Cache Clean and Invalidate by Virtual Address to Point of Coherency (dc civac) instruction followed by a Data Synchronization Barrier (dsb sy) and an Instruction Synchronization Barrier (isb):
__asm__ volatile("dc civac, %0\n\tdsb sy\n\tisb" : : "r" (ptr) : "memory");