From 47c10976f0c72ea04f92c86cf4b3ca4b64390790 Mon Sep 17 00:00:00 2001 From: Lenni Hein Date: Thu, 20 Feb 2025 18:50:04 +0100 Subject: [PATCH] . --- CacheAttacks Bootcamp.md => README.md | 37 ++++++++++++++++++++++++--- src/cache_test.c | 20 ++++++++++----- src/recv.c | 25 +++++++++++++----- src/send.c | 11 +++++--- 4 files changed, 72 insertions(+), 21 deletions(-) rename CacheAttacks Bootcamp.md => README.md (64%) diff --git a/CacheAttacks Bootcamp.md b/README.md similarity index 64% rename from CacheAttacks Bootcamp.md rename to README.md index 5aa2eae..f2d9cbd 100644 --- a/CacheAttacks Bootcamp.md +++ b/README.md @@ -2,6 +2,8 @@ ### Primitive +in `./src/lib.c` sind folgende Primitive: + `time_maccess` misst wie lange der Zugriff auf die Speicheradresse `addr` dauert. ```C size_t time_maccess(void (* addr)(void)) @@ -53,16 +55,36 @@ void flush(void* addr) ```bash gcc -O0 cache_test.c primitive.c -o cache_test ``` -##### [Muster](./src/cache_test.c) +- CMake ist praktisch! siehe `./src/CMakeList.txt`. Verwenden durch `cmake .` und dann `make`. +Muster: `./src/cache_test.c` ### Block 2: Signale über den Cache `sharedlib.c` sieht so aus: ```C -... +void function(void) +{ asm volatile ( + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + ... ``` -Das kann man so kompilieren: + +Die Adresse von `function` kann also zum Flushen und Reloaded verwendet werden. +Da immer eine gesamte Cacheline geladen wird, sollte sich nichts anderes in dem selben 64Byte Block befinden. +Die Funktionen `padding_before` und `padding_after` sind beide 64 Byte groß, also eine Cacheline. +Damit kann dann auch gar nichts mehr schief gehen :) + +`sharedlib.c` kann man so kompilieren und linken: ```bash # sharedlib kompilieren @@ -73,9 +95,11 @@ 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: ```C +# in e.g. sender.c maccess((void *) function) ... ``` @@ -83,7 +107,12 @@ maccess((void *) function) - `taskset` zum 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 Zeitabstand von Flush zu Reload sollte MAXIMIERT werden! Dies ist das Zeitfenster, in welchem der Sender die Adresse(n) zurück in den Cache laden kann. - (Der Sender kann das Flushen übernehmen) - (Der Sender kann im gesamten Zeitabschnitt Flushen oder Laden, nicht nur einmal) -### Block 3: Pakete über den Cache als Medium \ No newline at end of file +### Block 3: Pakete über den Cache als Medium + +- Kann man irgendwie mehr als ein Bit gleichzeitig senden? ;) + +Muster: `./src/sender.c` und `./src/receiver.c` \ No newline at end of file diff --git a/src/cache_test.c b/src/cache_test.c index 8e53b4e..87ccca9 100644 --- a/src/cache_test.c +++ b/src/cache_test.c @@ -8,8 +8,10 @@ extern void flush(void* addr); extern void maccess(void* addr); extern uint64_t time_maccess(void* addr); -void measure_multiple_accesses(void (*addr)(void), size_t num_accesses, size_t* hits, size_t* misses) { - for (size_t i = 0; i < num_accesses; i++) { +void measure_multiple_accesses(void (*addr)(void), size_t num_accesses, size_t* hits, size_t* misses) +{ + for (size_t i = 0; i < num_accesses; i++) + { flush((void*) addr); misses[i] = time_maccess(addr); @@ -19,10 +21,12 @@ void measure_multiple_accesses(void (*addr)(void), size_t num_accesses, size_t* } } -size_t find_crossover_point(size_t* hits, size_t* misses, size_t num_accesses) { +size_t find_crossover_point(size_t* hits, size_t* misses, size_t num_accesses) +{ size_t hit_sum = 0, miss_sum = 0; - for (size_t i = 0; i < num_accesses; i++) { + for (size_t i = 0; i < num_accesses; i++) + { hit_sum += hits[i]; miss_sum += misses[i]; } @@ -33,16 +37,18 @@ size_t find_crossover_point(size_t* hits, size_t* misses, size_t num_accesses) { return (avg_hit + avg_miss) / 2; // Midpoint as threshold } -int main() { +int main() +{ size_t* hits = malloc(NUM_ACCESSES * sizeof(size_t)); size_t* misses = malloc(NUM_ACCESSES * sizeof(size_t)); - if (!hits || !misses) { + if (!hits || !misses) + { perror("Memory allocation failed"); return 1; } - measure_multiple_accesses((void*)maccess, NUM_ACCESSES, hits, misses); + measure_multiple_accesses((void*) maccess, NUM_ACCESSES, hits, misses); size_t threshold = find_crossover_point(hits, misses, NUM_ACCESSES); printf("Suggested threshold: %zu\n", threshold); diff --git a/src/recv.c b/src/recv.c index bc56d70..49398c1 100644 --- a/src/recv.c +++ b/src/recv.c @@ -16,23 +16,31 @@ volatile int sample_interval = 100; // Default: 100 µs volatile int threshold = 245; // Default: 245 cycles void signal_handler(int signo) { - if (signo == SIGALRM) { - if (byte_index >= BUFFER_SIZE) { + if (signo == SIGALRM) + { + // Check if buffer is full + if (byte_index >= BUFFER_SIZE) + { ualarm(0, 0); // Stop sampling printf("Buffer full. Stopping capture.\n"); return; } + // Receive a byte uint8_t byte = 0; - for (int i = 0; i < BITS; i++) { + for (int i = 0; i < BITS; i++) + { size_t time = time_maccess((void *) function + (i << 9)); - if (time < threshold) { + if (time < threshold) + { + // set the ith bit of byte to 1 if it was a cache hit byte |= (1 << i); } } // flush the cache - for (int i = 0; i < BITS; i++) { + for (int i = 0; i < BITS; i++) + { flush((void *) function + (i << 9)); } @@ -41,7 +49,8 @@ void signal_handler(int signo) { } int main(int argc, char *argv[]) { - if (argc < 3) { + if (argc < 3) + { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } @@ -51,7 +60,9 @@ int main(int argc, char *argv[]) { printf("Receiver started with sample interval: %d µs, threshold: %d cycles\n", sample_interval, threshold); - for (int i = 0; i < BITS; i++) { + // Flush the cache once before starting + for (int i = 0; i < BITS; i++) + { flush((void *) function + (i << 9)); } diff --git a/src/send.c b/src/send.c index 6064f96..d6ded57 100644 --- a/src/send.c +++ b/src/send.c @@ -14,8 +14,10 @@ volatile size_t buffer_len = 0; volatile size_t current_index = 0; volatile uint8_t byte_to_send = 0; -void signal_handler(int signo) { - if (signo == SIGALRM) { +void signal_handler(int signo) +{ + if (signo == SIGALRM) + { if (current_index < buffer_len) { byte_to_send = buffer[current_index++]; @@ -26,7 +28,8 @@ void signal_handler(int signo) { } } -int main(int argc, char *argv[]) { +int main(int argc, char *argv[]) +{ if (argc < 3) { fprintf(stderr, "Usage: %s \n", argv[0]); @@ -37,9 +40,11 @@ int main(int argc, char *argv[]) { buffer_len = strlen(argv[1]); int sample_interval = atoi(argv[2]); + // set up an alarm signal that triggers every timeframe signal(SIGALRM, signal_handler); ualarm(sample_interval, sample_interval); + // during the timeframe, continuously send the signal while (1) { for (int i = 0; i < BITS; i++)