2.2 KiB
2.2 KiB
Flush+Reload Covert Channel
Primitive
time_maccess misst wie lange der Zugriff auf die Speicheradresse addr dauert.
size_t time_maccess(void (* addr)(void))
{
uint64_t start, end, delta;
uint64_t lo, hi;
asm volatile ("LFENCE");
asm volatile ("RDTSC": "=a" (lo), "=d" (hi));
start = (hi<<32) | lo;
asm volatile ("LFENCE");
asm volatile ("movq (%0), %%rax\n"
:
: "c" (addr)
: "rax");
asm volatile ("LFENCE");
asm volatile ("RDTSC": "=a" (lo), "=d" (hi));
end = (hi<<32) | lo;
asm volatile ("LFENCE");
delta = end - start;
return delta;
}
maccess greift auf diese Speicheradresse addr zu.
void maccess(void* addr)
{
asm volatile ("movq (%0), %%rax\n"
:
: "c" (addr)
: "rax");
}
flush verdrängt die Speicheradresse addr aus dem Cache.
void flush(void* addr)
{
asm volatile ("clflush 0(%0)\n"
:
: "c" (addr)
: "rax");
}
Block 1: Messen der Timing-Differenzen + Threshold bestimmen
Tips
- am besten kompiliert man ohne Compileroptimierungen (
-O0):gcc -O0 cache_test.c primitive.c -o cache_test
Muster
Block 2: Signale über den Cache
sharedlib.c sieht so aus:
...
Das kann man so kompilieren:
# sharedlib kompilieren
gcc -fPIC -shared -O0 -o libsharedlib.so sharedlib.c
# sharedlib bei Sender und Empfänger linken
gcc -O0 sender.c primitive.c -L. -lsharedlib -o sender
gcc -O0 empfaenger.c primitive.c -L. -lsharedlib -o empfaenger
# ggfs. muss man noch den PATH exportieren
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
dann kann man function verwenden:
maccess((void *) function)
...
Tips
tasksetzum pinnen der Programme auf einen bestimmten CPU-Kern.- Verwendet man blockierenden Sleep um zu Takten, z.B.
clock_nanosleep, dann sollte man unbedingt darauf achten nicht eine Periodendauer zu schlafen, sondern nur bis zum nächsten Zeitabschnitt. Einfacher geht es mit nicht-blockierendem Sleep, z.B.ualarm. - (Der Sender kann das Flushen übernehmen)
- (Der Sender kann im gesamten Zeitabschnitt Flushen oder Laden, nicht nur einmal)